diff options
Diffstat (limited to 'generic/tkTextBTree.c')
-rw-r--r-- | generic/tkTextBTree.c | 1045 |
1 files changed, 855 insertions, 190 deletions
diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c index 9f3b8e5..964dfcd 100644 --- a/generic/tkTextBTree.c +++ b/generic/tkTextBTree.c @@ -4,14 +4,14 @@ * This file contains code that manages the B-tree representation * of text for Tk's text widget and implements character and * toggle segment types. - * + * * Copyright (c) 1992-1994 The Regents of the University of California. * Copyright (c) 1994-1995 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextBTree.c,v 1.14 2004/06/07 16:23:52 vincentdarley Exp $ + * RCS: @(#) $Id: tkTextBTree.c,v 1.15 2004/09/10 12:13:41 vincentdarley Exp $ */ #include "tkInt.h" @@ -19,6 +19,29 @@ #include "tkText.h" /* + * Implementation notes: + * + * Most of this file is independent of the text widget implementation + * and representation now. Without much effort this could be developed + * further into a new Tcl object type of which the Tk text widget is one + * example of a client. + * + * The B-tree is set up with a dummy last line of text which must not be + * displayed, and must _never_ have a non-zero pixel count. This dummy + * line is a historical convenience to avoid other code having to deal + * with NULL TkTextLines. Since Tk 8.5, with pixel line height + * calculations and peer widgets, this dummy line is becoming somewhat + * of a liability, and special case code has been required to deal with + * it. It is probably a good idea to investigate removing the dummy + * line completely. This could result in an overall simplification + * (although it would require new special case code to deal with the + * fact that '.text index end' would then not really point to a valid + * line, rather it would point to the beginning of a non-existent line + * one beyond all current lines - we could perhaps define that as a + * TkTextIndex with a NULL TkTextLine ptr). + */ + +/* * The data structure below keeps summary information about one tag as part * of the tag information in a node. */ @@ -55,11 +78,19 @@ typedef struct Node { int numChildren; /* Number of children of this node. */ int numLines; /* Total number of lines (leaves) in * the subtree rooted here. */ - int numPixels; /* Total number of vertical - * display pixels in the - * subtree rooted here. */ + int* numPixels; /* Array containing total number + * of vertical display pixels in + * the subtree rooted here, one + * entry for each peer widget. */ } Node; +/* + * Used to avoid having to allocate and deallocate arrays on the + * fly for commonly used procedures. Must be > 0. + */ + +#define PIXEL_CLIENTS 5 + /* * Upper and lower bounds on how many children a node may have: * rebalance when either of these limits is exceeded. MAX_CHILDREN @@ -70,13 +101,24 @@ typedef struct Node { #define MIN_CHILDREN 6 /* - * The data structure below defines an entire B-tree. + * The data structure below defines an entire B-tree. Since text + * widgets are the only current B-tree clients, 'clients' and + * 'pixelReferences' are identical. */ typedef struct BTree { Node *rootPtr; /* Pointer to root of B-tree. */ - TkText *textPtr; /* Used to find tagTable in consistency - * checking code */ + int clients; /* Number of clients of this + * B-tree */ + int pixelReferences; /* Number of clients of this + * B-tree which care about + * pixel heights */ + TkSharedText *sharedTextPtr; /* Used to find tagTable in consistency + * checking code, and to access + * list of all B-tree clients */ + int startEndCount; + TkTextLine **startEnd; + TkText **startEndRef; } BTree; /* @@ -116,6 +158,10 @@ int tkBTreeDebug = 0; * Forward declarations for procedures defined in this file: */ +static int AdjustPixelClient _ANSI_ARGS_((BTree *treePtr, + int defaultHeight, Node *nodePtr, TkTextLine *start, + TkTextLine *end, int useReference, + int newPixelReferences, int *counting)); static void ChangeNodeToggleCount _ANSI_ARGS_((Node *nodePtr, TkTextTag *tagPtr, int delta)); static void CharCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, @@ -126,7 +172,8 @@ static TkTextSegment * CharCleanupProc _ANSI_ARGS_((TkTextSegment *segPtr, TkTextLine *linePtr)); static TkTextSegment * CharSplitProc _ANSI_ARGS_((TkTextSegment *segPtr, int index)); -static void CheckNodeConsistency _ANSI_ARGS_((Node *nodePtr)); +static void CheckNodeConsistency _ANSI_ARGS_((Node *nodePtr, + int references)); static void CleanupLine _ANSI_ARGS_((TkTextLine *linePtr)); static void DeleteSummaries _ANSI_ARGS_((Summary *tagPtr)); static void DestroyNode _ANSI_ARGS_((Node *nodePtr)); @@ -135,7 +182,10 @@ static TkTextSegment * FindTagEnd _ANSI_ARGS_((TkTextBTree tree, static void IncCount _ANSI_ARGS_((TkTextTag *tagPtr, int inc, TagInfo *tagInfoPtr)); static void Rebalance _ANSI_ARGS_((BTree *treePtr, Node *nodePtr)); -static void RecomputeNodeCounts _ANSI_ARGS_((Node *nodePtr)); +static void RecomputeNodeCounts _ANSI_ARGS_((BTree *treePtr, + Node *nodePtr)); +static void RemovePixelClient _ANSI_ARGS_((BTree *treePtr, + Node *nodePtr, int overwriteWithLast)); static TkTextSegment * SplitSeg _ANSI_ARGS_((TkTextIndex *indexPtr)); static void ToggleCheckProc _ANSI_ARGS_((TkTextSegment *segPtr, TkTextLine *linePtr)); @@ -147,6 +197,14 @@ static void ToggleLineChangeProc _ANSI_ARGS_((TkTextSegment *segPtr, TkTextLine *linePtr)); static TkTextSegment * FindTagStart _ANSI_ARGS_((TkTextBTree tree, TkTextTag *tagPtr, TkTextIndex *indexPtr)); +static void AdjustStartEndRefs _ANSI_ARGS_((BTree *treePtr, + TkText *textPtr, int action)); + +/* + * Actions for use by AdjustStartEndRefs + */ +#define TEXT_ADD_REFS 1 +#define TEXT_REMOVE_REFS 2 /* * Type record for character segments: @@ -213,8 +271,8 @@ Tk_SegType tkTextToggleOffType = { */ TkTextBTree -TkBTreeCreate(textPtr) - TkText *textPtr; +TkBTreeCreate(sharedTextPtr) + TkSharedText *sharedTextPtr; { register BTree *treePtr; register Node *rootPtr; @@ -231,6 +289,7 @@ TkBTreeCreate(textPtr) rootPtr = (Node *) ckalloc(sizeof(Node)); linePtr = (TkTextLine *) ckalloc(sizeof(TkTextLine)); linePtr2 = (TkTextLine *) ckalloc(sizeof(TkTextLine)); + rootPtr->parentPtr = NULL; rootPtr->nextPtr = NULL; rootPtr->summaryPtr = NULL; @@ -238,12 +297,13 @@ TkBTreeCreate(textPtr) rootPtr->children.linePtr = linePtr; rootPtr->numChildren = 2; rootPtr->numLines = 2; - rootPtr->numPixels = textPtr->charHeight; - linePtr->pixelHeight = textPtr->charHeight; - linePtr->pixelCalculationEpoch = 0; - /* The last line permanently has a pixel height of zero */ - linePtr2->pixelHeight = 0; - linePtr2->pixelCalculationEpoch = 1; + /* + * The tree currently has no registered clients, so all pixel + * count pointers are simply NULL + */ + rootPtr->numPixels = NULL; + linePtr->pixels = NULL; + linePtr2->pixels = NULL; linePtr->parentPtr = rootPtr; linePtr->nextPtr = linePtr2; @@ -266,21 +326,152 @@ TkBTreeCreate(textPtr) segPtr->body.chars[1] = 0; treePtr = (BTree *) ckalloc(sizeof(BTree)); + treePtr->sharedTextPtr = sharedTextPtr; treePtr->rootPtr = rootPtr; - treePtr->textPtr = textPtr; - + treePtr->clients = 0; + treePtr->pixelReferences = 0; + treePtr->startEndCount = 0; + treePtr->startEnd = NULL; + treePtr->startEndRef = NULL; + return (TkTextBTree) treePtr; } /* *---------------------------------------------------------------------- * + * TkBTreeAddClient -- + * + * This procedure is called to provide a client with access to + * a given B-tree. If the client wishes to make use of the + * B-tree's pixel height storage, caching and calculation + * mechanisms, then a non-negative 'defaultHeight' must be + * provided. In this case the return value is a pixel tree + * reference which must be provided in all of the B-tree API which + * refers to or modifies pixel heights: + * + * TkBTreeAdjustPixelHeight, + * TkBTreeFindPixelLine, + * TkBTreeNumPixels, + * TkBTreePixelsTo, + * (and two private functions AdjustPixelClient, RemovePixelClient). + * + * If this is not provided, then the above functions must + * never be called for this client. + * + * Results: + * The return value is the pixelReference used by the B-tree to + * refer to pixel counts for the new client. It should be stored + * by the caller. If defaultHeight was negative, then the return + * value will be -1. + * + * Side effects: + * Memory may be allocated and initialized. + * + *---------------------------------------------------------------------- + */ + +void +TkBTreeAddClient(tree, textPtr, defaultHeight) + TkTextBTree tree; /* B-tree to add a client to */ + TkText *textPtr; /* Client to add */ + int defaultHeight; /* Default line height for the new + * client, or -1 if no pixel + * heights are to be kept. */ +{ + register BTree *treePtr = (BTree*) tree; + + if (treePtr == NULL) { + Tcl_Panic("NULL treePtr in TkBTreeAddClient"); + } + + if (textPtr->start != NULL || textPtr->end != NULL) { + AdjustStartEndRefs(treePtr, textPtr, TEXT_ADD_REFS); + } + + if (defaultHeight >= 0) { + TkTextLine *end; + int counting = (textPtr->start == NULL ? 1 : 0); + int useReference = treePtr->pixelReferences; + /* + * We must set the 'end' value in AdjustPixelClient so that + * the last dummy line in the B-tree doesn't contain + * a pixel height. + */ + end = textPtr->end; + if (end == NULL) { + end = TkBTreeFindLine(tree, NULL, TkBTreeNumLines(tree, NULL)); + } + AdjustPixelClient(treePtr, defaultHeight, treePtr->rootPtr, + textPtr->start, end, useReference, + 1 + useReference, &counting); + + textPtr->pixelReference = useReference; + treePtr->pixelReferences++; + } else { + textPtr->pixelReference = -1; + } + treePtr->clients++; +} + +/* + *---------------------------------------------------------------------- + * + * TkBTreeClientRangeChanged -- + * + * Called when the -startline or -endline options of a text + * widget client of the B-tree have changed. + * + * Results: + * None. + * + * Side effects: + * Lots of processing of the B-tree is done, with potential + * for memory to be allocated and initialized for the pixel + * heights of the widget. + * + *---------------------------------------------------------------------- + */ + +void +TkBTreeClientRangeChanged(textPtr, defaultHeight) + TkText *textPtr; /* Client whose start, end have + * changed. */ + int defaultHeight; /* Default line height for the new + * client, or -1 if no pixel + * heights are to be kept. */ +{ + TkTextLine *end; + BTree *treePtr = (BTree*) textPtr->sharedTextPtr->tree; + + int counting = (textPtr->start == NULL ? 1 : 0); + int useReference = textPtr->pixelReference; + + AdjustStartEndRefs(treePtr, textPtr, TEXT_ADD_REFS | TEXT_REMOVE_REFS); + /* + * We must set the 'end' value in AdjustPixelClient so that + * the last dummy line in the B-tree doesn't contain + * a pixel height. + */ + end = textPtr->end; + if (end == NULL) { + end = TkBTreeFindLine(textPtr->sharedTextPtr->tree, + NULL, TkBTreeNumLines(textPtr->sharedTextPtr->tree, NULL)); + } + AdjustPixelClient(treePtr, defaultHeight, treePtr->rootPtr, + textPtr->start, end, useReference, + treePtr->pixelReferences, &counting); +} + +/* + *---------------------------------------------------------------------- + * * TkBTreeDestroy -- * * Delete a B-tree, recycling all of the storage it contains. * * Results: - * The tree given by treePtr is deleted. TreePtr should never + * The tree is deleted, so 'tree' should never * again be used. * * Side effects: @@ -291,17 +482,347 @@ TkBTreeCreate(textPtr) void TkBTreeDestroy(tree) - TkTextBTree tree; /* Pointer to tree to delete. */ + TkTextBTree tree; /* Tree to clean up */ { BTree *treePtr = (BTree *) tree; + /* + * There's no need to loop over each client of the tree, calling + * 'TkBTreeRemoveClient', since the 'DestroyNode' will clean + * everything up itself. + */ + DestroyNode(treePtr->rootPtr); + if (treePtr->startEnd != NULL) { + ckfree((char *) treePtr->startEnd); + ckfree((char *) treePtr->startEndRef); + } ckfree((char *) treePtr); } /* *---------------------------------------------------------------------- * + * TkBTreeRemoveClient -- + * + * Remove a client widget from its B-tree, cleaning up the pixel + * arrays which it uses if necessary. If this is the last such + * widget, we also destroy the whole tree. + * + * Results: + * All tree-specific aspects of the given client are deleted. + * If no more references exist, then the given tree is also + * deleted (in which case 'tree' must not be used again). + * + * Side effects: + * Memory may be freed. + * + *---------------------------------------------------------------------- + */ + +void +TkBTreeRemoveClient(tree, textPtr) + TkTextBTree tree; /* Tree to remove client from */ + TkText *textPtr; /* Client to remove. */ +{ + BTree *treePtr = (BTree *) tree; + int pixelReference = textPtr->pixelReference; + + if (treePtr->clients == 1) { + /* The last reference to the tree */ + DestroyNode(treePtr->rootPtr); + ckfree((char *) treePtr); + return; + } else if (pixelReference == -1) { + /* A client which doesn't care about pixels */ + treePtr->clients--; + } else { + /* Clean up pixel data for the given reference */ + + if (pixelReference == (treePtr->pixelReferences-1)) { + /* + * The widget we're removing has the last index, + * so deletion is easier. + */ + RemovePixelClient(treePtr, treePtr->rootPtr, -1); + } else { + TkText *adjustPtr; + + RemovePixelClient(treePtr, treePtr->rootPtr, pixelReference); + + /* + * Now we need to adjust the 'pixelReference' of the + * peer widget whose storage we've just moved. + */ + adjustPtr = treePtr->sharedTextPtr->peers; + while (adjustPtr != NULL) { + if (adjustPtr->pixelReference == (treePtr->pixelReferences-1)) { + adjustPtr->pixelReference = pixelReference; + break; + } + adjustPtr = adjustPtr->next; + } + if (adjustPtr == NULL) { + Tcl_Panic("Couldn't find text widget with correct reference"); + } + } + treePtr->pixelReferences--; + treePtr->clients--; + } + + if (textPtr->start != NULL || textPtr->end != NULL) { + AdjustStartEndRefs(treePtr, textPtr, TEXT_REMOVE_REFS); + } +} + +/* + *---------------------------------------------------------------------- + * + * AdjustStartEndRefs -- + * + * Modify B-tree's cache of start, end lines for the given text + * widget. + * + * Results: + * None. + * + * Side effects: + * The number of cached items may change + * (treePtr->startEndCount). + * + *---------------------------------------------------------------------- + */ + +static void +AdjustStartEndRefs(treePtr, textPtr, action) + BTree *treePtr; /* The entire B-tree */ + TkText *textPtr; /* The text widget for which we want to + * adjust it's start and end cache. */ + int action; /* Action to perform */ +{ + if (action & TEXT_REMOVE_REFS) { + int i = 0; + int count = 0; + + while (i < treePtr->startEndCount) { + if (i != count) { + treePtr->startEnd[count] = treePtr->startEnd[i]; + treePtr->startEndRef[count] = treePtr->startEndRef[i]; + } + if (treePtr->startEndRef[i] != textPtr) { + count++; + } + i++; + } + treePtr->startEndCount = count; + treePtr->startEnd = (TkTextLine**)ckrealloc((char*)treePtr->startEnd, + sizeof(TkTextLine*)*count); + treePtr->startEndRef = (TkText**)ckrealloc((char*)treePtr->startEndRef, + sizeof(TkText*)*count); + } + if ((action & TEXT_ADD_REFS) + && (textPtr->start != NULL || textPtr->end != NULL)) { + int count; + + if (textPtr->start != NULL) treePtr->startEndCount++; + if (textPtr->end != NULL) treePtr->startEndCount++; + + count = treePtr->startEndCount; + + treePtr->startEnd = (TkTextLine**)ckrealloc((char*)treePtr->startEnd, + sizeof(TkTextLine*)*count); + treePtr->startEndRef = (TkText**)ckrealloc((char*)treePtr->startEndRef, + sizeof(TkText*)*count); + + if (textPtr->start != NULL) { + count--; + treePtr->startEnd[count] = textPtr->start; + treePtr->startEndRef[count] = treePtr->sharedTextPtr->peers; + } + if (textPtr->end != NULL) { + count--; + treePtr->startEnd[count] = textPtr->end; + treePtr->startEndRef[count] = treePtr->sharedTextPtr->peers; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * AdjustPixelClient -- + * + * Utility procedure used to update all data structures for the + * existence of a new peer widget based on this B-tree, or for + * the modification of the start, end lines of an existing peer + * widget. + * + * Immediately _after_ calling this, treePtr->clients and + * treePtr->pixelReferences should be adjusted if needed (i.e. + * if this is a new peer). + * + * Results: + * None. + * + * Side effects: + * All the storage for Nodes and TkTextLines in the tree may + * be adjusted. + * + *---------------------------------------------------------------------- + */ + +static int +AdjustPixelClient(treePtr, defaultHeight, nodePtr, start, end, + useReference, newPixelReferences, counting) + BTree *treePtr; /* Pointer to tree */ + int defaultHeight; /* Default pixel line + * height, which can be zero. */ + Node *nodePtr; /* Adjust from this node + * downwards */ + TkTextLine *start; /* First line for this pixel + * client */ + TkTextLine *end; /* Last line for this pixel + * client */ + int useReference; /* pixel reference for the + * client we are adding or + * changing */ + int newPixelReferences; /* New number of pixel + * references to this B-tree */ + int *counting; /* References an integer which + * is zero if we're outside the + * relevant range for this + * client, and 1 if we're + * inside. */ +{ + int pixelCount = 0; + + /* + * Traverse entire tree down from nodePtr, reallocating pixel + * structures for each Node and TkTextLine, adding room for the new + * peer's pixel information (1 extra int per Node, 2 extra ints per + * TkTextLine). Also copy the information from the last peer into + * the new space (so it contains something sensible). + */ + + if (nodePtr->level != 0) { + Node *loopPtr = nodePtr->children.nodePtr; + while (loopPtr != NULL) { + pixelCount += AdjustPixelClient(treePtr, defaultHeight, loopPtr, + start, end, useReference, + newPixelReferences, counting); + loopPtr = loopPtr->nextPtr; + } + } else { + register TkTextLine *linePtr = nodePtr->children.linePtr; + + while (linePtr != NULL) { + if (!*counting && (linePtr == start)) { + *counting = 1; + } + if (*counting && (linePtr == end)) { + *counting = 0; + } + if (newPixelReferences != treePtr->pixelReferences) { + linePtr->pixels = (int*)ckrealloc((char*)linePtr->pixels, + sizeof(int)*2*newPixelReferences); + } + /* + * Notice that for the very last line, we are never counting + * and therefore this always has a height of 0 and an epoch + * of 1. + */ + linePtr->pixels[2*useReference] = (*counting ? defaultHeight : 0); + linePtr->pixels[1+2*useReference] = (*counting ? 0 : 1); + pixelCount += linePtr->pixels[2*useReference]; + + linePtr = linePtr->nextPtr; + } + } + if (newPixelReferences != treePtr->pixelReferences) { + nodePtr->numPixels = (int*)ckrealloc((char*)nodePtr->numPixels, + sizeof(int)*newPixelReferences); + } + nodePtr->numPixels[useReference] = pixelCount; + return pixelCount; +} + +/* + *---------------------------------------------------------------------- + * + * RemovePixelClient -- + * + * Utility procedure used to update all data structures for the + * removal of a peer widget which used to be based on this B-tree. + * + * Immediately _after_ calling this, treePtr->clients should + * be decremented. + * + * Results: + * None. + * + * Side effects: + * All the storage for Nodes and TkTextLines in the tree may + * be adjusted. + * + *---------------------------------------------------------------------- + */ + +static void +RemovePixelClient(treePtr, nodePtr, overwriteWithLast) + BTree *treePtr; /* Pointer to tree */ + Node *nodePtr; /* Adjust from this node + * downwards */ + int overwriteWithLast; /* Over-write this peer widget's + * information with the last one + */ +{ + /* + * Traverse entire tree down from nodePtr, reallocating pixel + * structures for each Node and TkTextLine, removing space allocated + * for one peer. If 'overwriteWithLast' is not -1, then copy the + * information which was in the last slot on top of one of the + * others (i.e. it's not the last one we're deleting). + */ + + if (overwriteWithLast != -1) { + nodePtr->numPixels[overwriteWithLast] + = nodePtr->numPixels[treePtr->pixelReferences-1]; + } + if (treePtr->pixelReferences == 1) { + nodePtr->numPixels = NULL; + } else { + nodePtr->numPixels = (int*)ckrealloc((char*)nodePtr->numPixels, + sizeof(int)*(treePtr->pixelReferences-1)); + } + if (nodePtr->level != 0) { + nodePtr = nodePtr->children.nodePtr; + while (nodePtr != NULL) { + RemovePixelClient(treePtr, nodePtr, overwriteWithLast); + nodePtr = nodePtr->nextPtr; + } + } else { + register TkTextLine *linePtr = nodePtr->children.linePtr; + while (linePtr != NULL) { + if (overwriteWithLast != -1) { + linePtr->pixels[2*overwriteWithLast] + = linePtr->pixels[2*(treePtr->pixelReferences-1)]; + linePtr->pixels[1+2*overwriteWithLast] + = linePtr->pixels[1+2*(treePtr->pixelReferences-1)]; + } + if (treePtr->pixelReferences == 1) { + linePtr->pixels = NULL; + } else { + linePtr->pixels = (int*)ckrealloc((char*)linePtr->pixels, + sizeof(int)*2*(treePtr->pixelReferences-1)); + } + linePtr = linePtr->nextPtr; + } + } +} + +/* + *---------------------------------------------------------------------- + * * DestroyNode -- * * This is a recursive utility procedure used during the deletion @@ -318,7 +839,7 @@ TkBTreeDestroy(tree) static void DestroyNode(nodePtr) - register Node *nodePtr; + register Node *nodePtr; /* Destroy from this node downwards */ { if (nodePtr->level == 0) { TkTextLine *linePtr; @@ -332,6 +853,7 @@ DestroyNode(nodePtr) linePtr->segPtr = segPtr->nextPtr; (*segPtr->typePtr->deleteProc)(segPtr, linePtr, 1); } + ckfree((char *) linePtr->pixels); ckfree((char *) linePtr); } } else { @@ -344,6 +866,7 @@ DestroyNode(nodePtr) } } DeleteSummaries(nodePtr->summaryPtr); + ckfree((char *) nodePtr->numPixels); ckfree((char *) nodePtr); } @@ -396,7 +919,8 @@ DeleteSummaries(summaryPtr) */ int -TkBTreeAdjustPixelHeight(linePtr, newPixelHeight) +TkBTreeAdjustPixelHeight(textPtr, linePtr, newPixelHeight) + CONST TkText *textPtr; /* Client of the B-tree */ register TkTextLine *linePtr; /* The logical line to update */ int newPixelHeight; /* The line's known height * in pixels */ @@ -404,8 +928,9 @@ TkBTreeAdjustPixelHeight(linePtr, newPixelHeight) register Node *nodePtr; int changeToPixelCount; /* Counts change to total number of * pixels in file. */ - - changeToPixelCount = newPixelHeight - linePtr->pixelHeight; + int pixelReference = textPtr->pixelReference; + + changeToPixelCount = newPixelHeight - linePtr->pixels[2*pixelReference]; /* * Increment the pixel counts in all the parent nodes of the @@ -413,16 +938,16 @@ TkBTreeAdjustPixelHeight(linePtr, newPixelHeight) */ nodePtr = linePtr->parentPtr; - nodePtr->numPixels += changeToPixelCount; + nodePtr->numPixels[pixelReference] += changeToPixelCount; while (nodePtr->parentPtr != NULL) { nodePtr = nodePtr->parentPtr; - nodePtr->numPixels += changeToPixelCount; + nodePtr->numPixels[pixelReference] += changeToPixelCount; } - linePtr->pixelHeight = newPixelHeight; + linePtr->pixels[2*pixelReference] = newPixelHeight; - return nodePtr->numPixels; + return nodePtr->numPixels[pixelReference]; } /* @@ -444,7 +969,8 @@ TkBTreeAdjustPixelHeight(linePtr, newPixelHeight) */ void -TkBTreeInsertChars(indexPtr, string) +TkBTreeInsertChars(tree, indexPtr, string) + TkTextBTree tree; /* Tree to insert into */ register TkTextIndex *indexPtr; /* Indicates where to insert text. * When the procedure returns, this * index is no longer valid because @@ -471,9 +997,12 @@ TkBTreeInsertChars(indexPtr, string) * one in current chunk. */ int changeToLineCount; /* Counts change to total number of * lines in file. */ - int changeToPixelCount; /* Counts change to total number of + int *changeToPixelCount; /* Counts change to total number of * pixels in file. */ - + int ref; + int pixels[PIXEL_CLIENTS]; + + BTree *treePtr = (BTree*)tree; prevPtr = SplitSeg(indexPtr); linePtr = indexPtr->linePtr; curPtr = prevPtr; @@ -485,7 +1014,16 @@ TkBTreeInsertChars(indexPtr, string) */ changeToLineCount = 0; - changeToPixelCount = 0; + if (treePtr->pixelReferences > PIXEL_CLIENTS) { + changeToPixelCount = (int*) ckalloc(sizeof(int) * + treePtr->pixelReferences); + } else { + changeToPixelCount = pixels; + } + for (ref = 0; ref < treePtr->pixelReferences; ref++) { + changeToPixelCount[ref] = 0; + } + while (*string != 0) { for (eol = string; *eol != 0; eol++) { if (*eol == '\n') { @@ -517,22 +1055,27 @@ TkBTreeInsertChars(indexPtr, string) */ newLinePtr = (TkTextLine *) ckalloc(sizeof(TkTextLine)); + newLinePtr->pixels = + (int*) ckalloc(sizeof(int)*2*treePtr->pixelReferences); + newLinePtr->parentPtr = linePtr->parentPtr; newLinePtr->nextPtr = linePtr->nextPtr; linePtr->nextPtr = newLinePtr; newLinePtr->segPtr = segPtr->nextPtr; /* * Set up a starting default height, which will be re-adjusted - * later + * later. We need to do this for each referenced widget */ - newLinePtr->pixelHeight = linePtr->pixelHeight; - newLinePtr->pixelCalculationEpoch = 0; + for (ref = 0; ref < treePtr->pixelReferences; ref++) { + newLinePtr->pixels[2*ref] = linePtr->pixels[2*ref]; + newLinePtr->pixels[1+2*ref] = 0; + changeToPixelCount[ref] += newLinePtr->pixels[2*ref]; + } segPtr->nextPtr = NULL; linePtr = newLinePtr; curPtr = NULL; changeToLineCount++; - changeToPixelCount += newLinePtr->pixelHeight; string = eol; } @@ -543,7 +1086,7 @@ TkBTreeInsertChars(indexPtr, string) * the function is robust to that case anyway. (We must never * re-calculated the line height of the last line). */ - TkTextInvalidateLineMetrics(((BTree*)indexPtr->tree)->textPtr, + TkTextInvalidateLineMetrics(treePtr->sharedTextPtr, NULL, indexPtr->linePtr, changeToLineCount, TK_TEXT_INVALIDATE_INSERT); @@ -565,12 +1108,18 @@ TkBTreeInsertChars(indexPtr, string) for (nodePtr = linePtr->parentPtr ; nodePtr != NULL; nodePtr = nodePtr->parentPtr) { nodePtr->numLines += changeToLineCount; - nodePtr->numPixels += changeToPixelCount; + for (ref = 0; ref < treePtr->pixelReferences; ref++) { + nodePtr->numPixels[ref] += changeToPixelCount[ref]; + } + } + if (treePtr->pixelReferences > PIXEL_CLIENTS) { + ckfree((char*)changeToPixelCount); } + nodePtr = linePtr->parentPtr; nodePtr->numChildren += changeToLineCount; if (nodePtr->numChildren > MAX_CHILDREN) { - Rebalance((BTree *) indexPtr->tree, nodePtr); + Rebalance(treePtr, nodePtr); } if (tkBTreeDebug) { @@ -715,7 +1264,8 @@ CleanupLine(linePtr) */ void -TkBTreeDeleteChars(index1Ptr, index2Ptr) +TkBTreeDeleteChars(tree, index1Ptr, index2Ptr) + TkTextBTree tree; /* Tree to delete from */ register TkTextIndex *index1Ptr; /* Indicates first character that is * to be deleted. */ register TkTextIndex *index2Ptr; /* Indicates character just after the @@ -729,6 +1279,8 @@ TkBTreeDeleteChars(index1Ptr, index2Ptr) TkTextLine *curLinePtr; Node *curNodePtr, *nodePtr; int changeToLineCount = 0; + int ref; + BTree *treePtr = (BTree*)tree; /* * Tricky point: split at index2Ptr first; otherwise the split @@ -767,7 +1319,7 @@ TkBTreeDeleteChars(index1Ptr, index2Ptr) * (unless it's the starting line for the range). */ - nextLinePtr = TkBTreeNextLine(curLinePtr); + nextLinePtr = TkBTreeNextLine(NULL, curLinePtr); if (curLinePtr != index1Ptr->linePtr) { if (curNodePtr == index1Ptr->linePtr->parentPtr) { index1Ptr->linePtr->nextPtr = curLinePtr->nextPtr; @@ -777,10 +1329,35 @@ TkBTreeDeleteChars(index1Ptr, index2Ptr) for (nodePtr = curNodePtr; nodePtr != NULL; nodePtr = nodePtr->parentPtr) { nodePtr->numLines--; - nodePtr->numPixels -= curLinePtr->pixelHeight; + for (ref = 0; ref < treePtr->pixelReferences; ref++) { + nodePtr->numPixels[ref] -= curLinePtr->pixels[2*ref]; + } } changeToLineCount++; curNodePtr->numChildren--; + /* Check if we need to adjust any partial clients */ + if (treePtr->startEnd != NULL) { + int checkCount = 0; + while (checkCount < treePtr->startEndCount) { + if (treePtr->startEnd[checkCount] == curLinePtr) { + TkText *peer = treePtr->startEndRef[checkCount]; + /* + * We're deleting a line which is the start + * or end of a current client. This means + * we need to adjust that client. + */ + treePtr->startEnd[checkCount] = nextLinePtr; + if (peer->start == curLinePtr) { + peer->start = nextLinePtr; + } + if (peer->end == curLinePtr) { + peer->end = nextLinePtr; + } + } + checkCount++; + } + } + ckfree((char *) curLinePtr->pixels); ckfree((char *) curLinePtr); } curLinePtr = nextLinePtr; @@ -851,7 +1428,9 @@ TkBTreeDeleteChars(index1Ptr, index2Ptr) for (nodePtr = curNodePtr; nodePtr != NULL; nodePtr = nodePtr->parentPtr) { nodePtr->numLines--; - nodePtr->numPixels -= index2Ptr->linePtr->pixelHeight; + for (ref = 0; ref < treePtr->pixelReferences; ref++) { + nodePtr->numPixels[ref] -= index2Ptr->linePtr->pixels[2*ref]; + } } changeToLineCount++; curNodePtr->numChildren--; @@ -864,6 +1443,36 @@ TkBTreeDeleteChars(index1Ptr, index2Ptr) } prevLinePtr->nextPtr = index2Ptr->linePtr->nextPtr; } + /* + * Check if we need to adjust any partial clients. In this case + * if we're deleting the line, we actually move back to the + * previous line for our (start,end) storage. We do this + * because we still want the portion of the second line that + * still exists to be in the start,end range. + */ + if (treePtr->startEnd != NULL) { + int checkCount = 0; + + while (treePtr->startEnd[checkCount] != NULL) { + if (treePtr->startEnd[checkCount] == index2Ptr->linePtr) { + TkText *peer = treePtr->startEndRef[checkCount]; + /* + * We're deleting a line which is the start + * or end of a current client. This means + * we need to adjust that client. + */ + treePtr->startEnd[checkCount] = index1Ptr->linePtr; + if (peer->start == index2Ptr->linePtr) { + peer->start = index1Ptr->linePtr; + } + if (peer->end == index2Ptr->linePtr) { + peer->end = index1Ptr->linePtr; + } + } + checkCount++; + } + } + ckfree((char *) index2Ptr->linePtr->pixels); ckfree((char *) index2Ptr->linePtr); Rebalance((BTree *) index2Ptr->tree, curNodePtr); @@ -881,8 +1490,8 @@ TkBTreeDeleteChars(index1Ptr, index2Ptr) * of text. I _believe_ that it isn't possible to get this far with * the last line, but it is good to be safe. */ - if (TkBTreeNextLine(index1Ptr->linePtr) != NULL) { - TkTextInvalidateLineMetrics(((BTree*)index1Ptr->tree)->textPtr, + if (TkBTreeNextLine(NULL, index1Ptr->linePtr) != NULL) { + TkTextInvalidateLineMetrics(treePtr->sharedTextPtr, NULL, index1Ptr->linePtr, changeToLineCount, TK_TEXT_INVALIDATE_DELETE); } @@ -915,21 +1524,42 @@ TkBTreeDeleteChars(index1Ptr, index2Ptr) */ TkTextLine * -TkBTreeFindLine(tree, line) +TkBTreeFindLine(tree, textPtr, line) TkTextBTree tree; /* B-tree in which to find line. */ + CONST TkText *textPtr; /* Relative to this client of the + * B-tree */ int line; /* Index of desired line. */ { BTree *treePtr = (BTree *) tree; register Node *nodePtr; register TkTextLine *linePtr; - int linesLeft; + if (treePtr == NULL) { + treePtr = (BTree *) textPtr->sharedTextPtr->tree; + } + nodePtr = treePtr->rootPtr; - linesLeft = line; if ((line < 0) || (line >= nodePtr->numLines)) { return NULL; } - + + /* + * Check for the any start/end offset for this text widget + */ + if (textPtr != NULL) { + if (textPtr->start != NULL) { + line += TkBTreeLinesTo(NULL, textPtr->start); + if (line >= nodePtr->numLines) { + return NULL; + } + } + if (textPtr->end != NULL) { + if (line > TkBTreeLinesTo(NULL, textPtr->end)) { + return NULL; + } + } + } + /* * Work down through levels of the tree until a node is found at * level 0. @@ -937,12 +1567,12 @@ TkBTreeFindLine(tree, line) while (nodePtr->level != 0) { for (nodePtr = nodePtr->children.nodePtr; - nodePtr->numLines <= linesLeft; + nodePtr->numLines <= line; nodePtr = nodePtr->nextPtr) { if (nodePtr == NULL) { Tcl_Panic("TkBTreeFindLine ran out of nodes"); } - linesLeft -= nodePtr->numLines; + line -= nodePtr->numLines; } } @@ -950,12 +1580,12 @@ TkBTreeFindLine(tree, line) * Work through the lines attached to the level-0 node. */ - for (linePtr = nodePtr->children.linePtr; linesLeft > 0; + for (linePtr = nodePtr->children.linePtr; line > 0; linePtr = linePtr->nextPtr) { if (linePtr == NULL) { Tcl_Panic("TkBTreeFindLine ran out of lines"); } - linesLeft -= 1; + line -= 1; } return linePtr; } @@ -985,24 +1615,25 @@ TkBTreeFindLine(tree, line) */ TkTextLine * -TkBTreeFindPixelLine(tree, pixels, pixelOffset) - TkTextBTree tree; /* B-tree in which to find line. */ - int pixels; /* Index of desired line. */ +TkBTreeFindPixelLine(tree, textPtr, pixels, pixelOffset) + TkTextBTree tree; /* B-tree to use. */ + CONST TkText *textPtr; /* Relative to this client of the + * B-tree */ + int pixels; /* Pixel index of desired line. */ int *pixelOffset; /* Used to return offset */ { BTree *treePtr = (BTree *) tree; register Node *nodePtr; register TkTextLine *linePtr; - int pixelsLeft; - + int pixelReference = textPtr->pixelReference; + nodePtr = treePtr->rootPtr; - pixelsLeft = pixels; - if ((pixels < 0) || (pixels > nodePtr->numPixels)) { + if ((pixels < 0) || (pixels > nodePtr->numPixels[pixelReference])) { return NULL; } - if (nodePtr->numPixels == 0) { + if (nodePtr->numPixels[pixelReference] == 0) { Tcl_Panic("TkBTreeFindPixelLine called with empty window"); } @@ -1013,12 +1644,12 @@ TkBTreeFindPixelLine(tree, pixels, pixelOffset) while (nodePtr->level != 0) { for (nodePtr = nodePtr->children.nodePtr; - nodePtr->numPixels <= pixelsLeft; + nodePtr->numPixels[pixelReference] <= pixels; nodePtr = nodePtr->nextPtr) { if (nodePtr == NULL) { Tcl_Panic("TkBTreeFindPixelLine ran out of nodes"); } - pixelsLeft -= nodePtr->numPixels; + pixels -= nodePtr->numPixels[pixelReference]; } } @@ -1027,15 +1658,15 @@ TkBTreeFindPixelLine(tree, pixels, pixelOffset) */ for (linePtr = nodePtr->children.linePtr; - linePtr->pixelHeight < pixelsLeft; + linePtr->pixels[2*pixelReference] < pixels; linePtr = linePtr->nextPtr) { if (linePtr == NULL) { Tcl_Panic("TkBTreeFindPixelLine ran out of lines"); } - pixelsLeft -= linePtr->pixelHeight; + pixels -= linePtr->pixels[2*pixelReference]; } if (pixelOffset != NULL && linePtr != NULL) { - *pixelOffset = pixelsLeft; + *pixelOffset = pixels; } return linePtr; } @@ -1060,16 +1691,22 @@ TkBTreeFindPixelLine(tree, pixels, pixelOffset) */ TkTextLine * -TkBTreeNextLine(linePtr) +TkBTreeNextLine(textPtr, linePtr) + CONST TkText *textPtr; /* Next line in the context of + * this client */ register TkTextLine *linePtr; /* Pointer to existing line in * B-tree. */ { register Node *nodePtr; if (linePtr->nextPtr != NULL) { - return linePtr->nextPtr; + if (textPtr != NULL && (linePtr == textPtr->end)) { + return NULL; + } else { + return linePtr->nextPtr; + } } - + /* * This was the last line associated with the particular parent node. * Search up the tree for the next node, then search down from that @@ -1111,7 +1748,9 @@ TkBTreeNextLine(linePtr) */ TkTextLine * -TkBTreePreviousLine(linePtr) +TkBTreePreviousLine(textPtr, linePtr) + TkText *textPtr; /* Relative to this client of the + * B-tree */ register TkTextLine *linePtr; /* Pointer to existing line in * B-tree. */ { @@ -1119,6 +1758,10 @@ TkBTreePreviousLine(linePtr) register Node *node2Ptr; register TkTextLine *prevPtr; + if (textPtr != NULL && textPtr->start == linePtr) { + return NULL; + } + /* * Find the line under this node just before the starting line. */ @@ -1166,7 +1809,7 @@ TkBTreePreviousLine(linePtr) /* *---------------------------------------------------------------------- * - * TkBTreePixels -- + * TkBTreePixelsTo -- * * Given a pointer to a line in a B-tree, return the numerical * pixel index of the top of that line (i.e. the result does @@ -1187,16 +1830,19 @@ TkBTreePreviousLine(linePtr) */ int -TkBTreePixels(linePtr) +TkBTreePixelsTo(textPtr, linePtr) + CONST TkText *textPtr; /* Relative to this client of the + * B-tree */ TkTextLine *linePtr; /* Pointer to existing line in * B-tree. */ { register TkTextLine *linePtr2; - register Node *nodePtr, *parentPtr, *nodePtr2; + register Node *nodePtr, *parentPtr; int index; + int pixelReference = textPtr->pixelReference; /* - * First count how many lines precede this one in its level-0 + * First count how many pixels precede this line in its level-0 * node. */ @@ -1205,25 +1851,26 @@ TkBTreePixels(linePtr) for (linePtr2 = nodePtr->children.linePtr; linePtr2 != linePtr; linePtr2 = linePtr2->nextPtr) { if (linePtr2 == NULL) { - Tcl_Panic("TkBTreePixels couldn't find line"); + Tcl_Panic("TkBTreePixelsTo couldn't find line"); } - index += linePtr2->pixelHeight; + index += linePtr2->pixels[2*pixelReference]; } /* * Now work up through the levels of the tree one at a time, - * counting how many lines are in nodes preceding the current + * counting how many pixels are in nodes preceding the current * node. */ for (parentPtr = nodePtr->parentPtr ; parentPtr != NULL; nodePtr = parentPtr, parentPtr = parentPtr->parentPtr) { + register Node *nodePtr2; for (nodePtr2 = parentPtr->children.nodePtr; nodePtr2 != nodePtr; nodePtr2 = nodePtr2->nextPtr) { if (nodePtr2 == NULL) { - Tcl_Panic("TkBTreePixels couldn't find node"); + Tcl_Panic("TkBTreePixelsTo couldn't find node"); } - index += nodePtr2->numPixels; + index += nodePtr2->numPixels[pixelReference]; } } return index; @@ -1232,7 +1879,7 @@ TkBTreePixels(linePtr) /* *---------------------------------------------------------------------- * - * TkBTreeLineIndex -- + * TkBTreeLinesTo -- * * Given a pointer to a line in a B-tree, return the numerical * index of that line. @@ -1248,7 +1895,9 @@ TkBTreePixels(linePtr) */ int -TkBTreeLineIndex(linePtr) +TkBTreeLinesTo(textPtr, linePtr) + CONST TkText *textPtr; /* Relative to this client of the + * B-tree */ TkTextLine *linePtr; /* Pointer to existing line in * B-tree. */ { @@ -1266,7 +1915,7 @@ TkBTreeLineIndex(linePtr) for (linePtr2 = nodePtr->children.linePtr; linePtr2 != linePtr; linePtr2 = linePtr2->nextPtr) { if (linePtr2 == NULL) { - Tcl_Panic("TkBTreeLineIndex couldn't find line"); + Tcl_Panic("TkBTreeLinesTo couldn't find line"); } index += 1; } @@ -1282,11 +1931,14 @@ TkBTreeLineIndex(linePtr) for (nodePtr2 = parentPtr->children.nodePtr; nodePtr2 != nodePtr; nodePtr2 = nodePtr2->nextPtr) { if (nodePtr2 == NULL) { - Tcl_Panic("TkBTreeLineIndex couldn't find node"); + Tcl_Panic("TkBTreeLinesTo couldn't find node"); } index += nodePtr2->numLines; } } + if (textPtr != NULL && textPtr->start != NULL) { + index -= TkBTreeLinesTo(NULL, textPtr->start); + } return index; } @@ -1352,8 +2004,7 @@ TkBTreeLinkSegment(segPtr, indexPtr) /* ARGSUSED */ void -TkBTreeUnlinkSegment(tree, segPtr, linePtr) - TkTextBTree tree; /* Tree containing segment. */ +TkBTreeUnlinkSegment(segPtr, linePtr) TkTextSegment *segPtr; /* Segment to be unlinked. */ TkTextLine *linePtr; /* Line that currently contains * segment. */ @@ -1951,8 +2602,8 @@ TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, searchPtr) } searchPtr->lastPtr = TkTextIndexToSeg(index2Ptr, (int *) NULL); searchPtr->tagPtr = tagPtr; - searchPtr->linesLeft = TkBTreeLineIndex(index2Ptr->linePtr) + 1 - - TkBTreeLineIndex(index1Ptr->linePtr); + searchPtr->linesLeft = TkBTreeLinesTo(NULL, index2Ptr->linePtr) + 1 + - TkBTreeLinesTo(NULL, index1Ptr->linePtr); searchPtr->allTags = (tagPtr == NULL); if (searchPtr->linesLeft == 1) { /* @@ -2042,7 +2693,7 @@ TkBTreeStartSearchBack(index1Ptr, index2Ptr, tagPtr, searchPtr) searchPtr->curIndex = index0; index1Ptr = &index0; } else { - TkTextIndexBackChars(NULL,index1Ptr, 1, &searchPtr->curIndex, + TkTextIndexBackChars(NULL, index1Ptr, 1, &searchPtr->curIndex, COUNT_INDICES); } searchPtr->segPtr = NULL; @@ -2054,7 +2705,7 @@ TkBTreeStartSearchBack(index1Ptr, index2Ptr, tagPtr, searchPtr) * at the second index specified by the user. */ - if ((TkBTreeLineIndex(index2Ptr->linePtr) == 0) && + if ((TkBTreeLinesTo(NULL, index2Ptr->linePtr) == 0) && (index2Ptr->byteIndex == 0)) { backOne = *index2Ptr; searchPtr->lastPtr = NULL; /* Signals special case for 1.0 */ @@ -2063,8 +2714,8 @@ TkBTreeStartSearchBack(index1Ptr, index2Ptr, tagPtr, searchPtr) searchPtr->lastPtr = TkTextIndexToSeg(&backOne, (int *) NULL); } searchPtr->tagPtr = tagPtr; - searchPtr->linesLeft = TkBTreeLineIndex(index1Ptr->linePtr) + 1 - - TkBTreeLineIndex(backOne.linePtr); + searchPtr->linesLeft = TkBTreeLinesTo(NULL, index1Ptr->linePtr) + 1 + - TkBTreeLinesTo(NULL, backOne.linePtr); searchPtr->allTags = (tagPtr == NULL); if (searchPtr->linesLeft == 1) { /* @@ -2588,9 +3239,12 @@ TkBTreeCharTagged(indexPtr, tagPtr) /* ARGSUSED */ TkTextTag ** -TkBTreeGetTags(indexPtr, numTagsPtr) +TkBTreeGetTags(indexPtr, textPtr, numTagsPtr) CONST TkTextIndex *indexPtr;/* Indicates a particular position in * the B-tree. */ + CONST TkText *textPtr; /* If non-NULL, then only return tags + * for this text widget (when there are + * peer widgets). */ int *numTagsPtr; /* Store number of tags found at this * location. */ { @@ -2664,13 +3318,17 @@ TkBTreeGetTags(indexPtr, numTagsPtr) /* * Go through the tag information and squash out all of the tags * that have even toggle counts (these tags exist before the point - * of interest, but not at the desired character itself). + * of interest, but not at the desired character itself). Also + * squash out all tags that don't belong to the requested widget. */ for (src = 0, dst = 0; src < tagInfo.numTags; src++) { if (tagInfo.counts[src] & 1) { - tagInfo.tagPtrs[dst] = tagInfo.tagPtrs[src]; - dst++; + CONST TkText *tagTextPtr = tagInfo.tagPtrs[src]->textPtr; + if (tagTextPtr == NULL || textPtr == NULL || tagTextPtr == textPtr) { + tagInfo.tagPtrs[dst] = tagInfo.tagPtrs[src]; + dst++; + } } } *numTagsPtr = dst; @@ -2688,17 +3346,21 @@ TkBTreeGetTags(indexPtr, numTagsPtr) * TkTextIsElided -- * * Special case to just return information about elided attribute. - * Specialized from TkBTreeGetTags(indexPtr, numTagsPtr) and + * Specialized from TkBTreeGetTags(indexPtr, textPtr, numTagsPtr) and * GetStyle(textPtr, indexPtr). Just need to keep track of * invisibility settings for each priority, pick highest one active * at end. * * Note that this returns all elide information up to and including * the given index (quite obviously). However, this does mean that - * indexPtr is a line-start and one then iterates from the beginning + * if indexPtr is a line-start and one then iterates from the beginning * of that line forwards, one will actually revisit the segPtrs of * size zero (for tag toggling, for example) which have already been * seen here. + * + * For this reason we fill in the fields 'segPtr' and 'segOffset' + * of elideInfo, enabling our caller easily to calculate + * incremental changes from where we left off. * * Results: * Returns whether this text should be elided or not. @@ -2738,7 +3400,7 @@ TkTextIsElided(textPtr, indexPtr, elideInfo) infoPtr->elide = 0; /* if nobody says otherwise, it's visible */ infoPtr->tagCnts = infoPtr->deftagCnts; infoPtr->tagPtrs = infoPtr->deftagPtrs; - infoPtr->numTags = textPtr->numTags; + infoPtr->numTags = textPtr->sharedTextPtr->numTags; /* Almost always avoid malloc, so stay out of system calls */ if (LOTSA_TAGS < infoPtr->numTags) { @@ -2774,7 +3436,8 @@ TkTextIsElided(textPtr, indexPtr, elideInfo) * so that our caller knows where to start. */ infoPtr->segPtr = segPtr; - + infoPtr->segOffset = index; + /* * Record toggles for tags in lines that are predecessors of * indexPtr->linePtr but under the same level-0 node. @@ -2829,13 +3492,12 @@ TkTextIsElided(textPtr, indexPtr, elideInfo) infoPtr->elidePriority = -1; for (i = infoPtr->numTags-1; i >=0; i--) { if (infoPtr->tagCnts[i] & 1) { -#ifndef ALWAYS_SHOW_SELECTION - /* who would make the selection elided? */ + /* Who would make the selection elided? */ if ((tagPtr == textPtr->selTagPtr) - && !(textPtr->flags & GOT_FOCUS)) { + && !(textPtr->flags & GOT_FOCUS) + && (textPtr->inactiveSelBorder == NULL)) { continue; } -#endif infoPtr->elide = infoPtr->tagPtrs[i]->elide; /* Note: i == infoPtr->tagPtrs[i]->priority */ infoPtr->elidePriority = i; @@ -2987,7 +3649,7 @@ TkBTreeCheck(tree) /* * Make sure that the tag toggle counts and the tag root pointers are OK. */ - for (entryPtr = Tcl_FirstHashEntry(&treePtr->textPtr->tagTable, &search); + for (entryPtr = Tcl_FirstHashEntry(&treePtr->sharedTextPtr->tagTable, &search); entryPtr != NULL ; entryPtr = Tcl_NextHashEntry(&search)) { tagPtr = (TkTextTag *) Tcl_GetHashValue(entryPtr); nodePtr = tagPtr->tagRootPtr; @@ -3045,7 +3707,7 @@ TkBTreeCheck(tree) */ nodePtr = treePtr->rootPtr; - CheckNodeConsistency(treePtr->rootPtr); + CheckNodeConsistency(treePtr->rootPtr, treePtr->pixelReferences); /* * Make sure that there are at least two lines in the text and @@ -3113,15 +3775,19 @@ TkBTreeCheck(tree) */ static void -CheckNodeConsistency(nodePtr) +CheckNodeConsistency(nodePtr, references) register Node *nodePtr; /* Node whose subtree should be * checked. */ + int references; /* Number of referring widgets + * which have pixel counts. */ { register Node *childNodePtr; register Summary *summaryPtr, *summaryPtr2; register TkTextLine *linePtr; register TkTextSegment *segPtr; - int numChildren, numLines, numPixels, toggleCount, minChildren; + int numChildren, numLines, toggleCount, minChildren, i; + int *numPixels; + int pixels[PIXEL_CLIENTS]; if (nodePtr->parentPtr != NULL) { minChildren = MIN_CHILDREN; @@ -3138,7 +3804,15 @@ CheckNodeConsistency(nodePtr) numChildren = 0; numLines = 0; - numPixels = 0; + if (references > PIXEL_CLIENTS) { + numPixels = (int*)ckalloc(sizeof(int)*references); + } else { + numPixels = pixels; + } + for (i = 0; i<references; i++) { + numPixels[i] = 0; + } + if (nodePtr->level == 0) { for (linePtr = nodePtr->children.linePtr; linePtr != NULL; linePtr = linePtr->nextPtr) { @@ -3166,7 +3840,9 @@ CheckNodeConsistency(nodePtr) } numChildren++; numLines++; - numPixels += linePtr->pixelHeight; + for (i = 0; i<references; i++) { + numPixels[i] += linePtr->pixels[2*i]; + } } } else { for (childNodePtr = nodePtr->children.nodePtr; childNodePtr != NULL; @@ -3178,7 +3854,7 @@ CheckNodeConsistency(nodePtr) Tcl_Panic("CheckNodeConsistency: level mismatch (%d %d)", nodePtr->level, childNodePtr->level); } - CheckNodeConsistency(childNodePtr); + CheckNodeConsistency(childNodePtr, references); for (summaryPtr = childNodePtr->summaryPtr; summaryPtr != NULL; summaryPtr = summaryPtr->nextPtr) { for (summaryPtr2 = nodePtr->summaryPtr; ; @@ -3198,7 +3874,9 @@ CheckNodeConsistency(nodePtr) } numChildren++; numLines += childNodePtr->numLines; - numPixels += childNodePtr->numPixels; + for (i = 0; i<references; i++) { + numPixels[i] += childNodePtr->numPixels[i]; + } } } if (numChildren != nodePtr->numChildren) { @@ -3209,11 +3887,16 @@ CheckNodeConsistency(nodePtr) Tcl_Panic("CheckNodeConsistency: mismatch in numLines (%d %d)", numLines, nodePtr->numLines); } - if (numPixels != nodePtr->numPixels) { - Tcl_Panic("CheckNodeConsistency: mismatch in numPixels (%d %d)", - numPixels, nodePtr->numPixels); + for (i = 0; i<references; i++) { + if (numPixels[i] != nodePtr->numPixels[i]) { + Tcl_Panic("CheckNodeConsistency: mismatch in numPixels (%d %d) for widget (%d)", + numPixels[i], nodePtr->numPixels[i], i); + } } - + if (references > PIXEL_CLIENTS) { + ckfree((char*)numPixels); + } + for (summaryPtr = nodePtr->summaryPtr; summaryPtr != NULL; summaryPtr = summaryPtr->nextPtr) { if (summaryPtr->tagPtr->toggleCount == summaryPtr->toggleCount) { @@ -3319,11 +4002,20 @@ Rebalance(treePtr, nodePtr) newPtr->children.nodePtr = nodePtr; newPtr->numChildren = 1; newPtr->numLines = nodePtr->numLines; - newPtr->numPixels = nodePtr->numPixels; - RecomputeNodeCounts(newPtr); + newPtr->numPixels = (int*) ckalloc(sizeof(int)* + treePtr->pixelReferences); + for (i=0; i<treePtr->pixelReferences; i++) { + newPtr->numPixels[i] = nodePtr->numPixels[i]; + } + RecomputeNodeCounts(treePtr, newPtr); treePtr->rootPtr = newPtr; } newPtr = (Node *) ckalloc(sizeof(Node)); + newPtr->numPixels = (int*) ckalloc(sizeof(int)* + treePtr->pixelReferences); + for (i=0; i<treePtr->pixelReferences; i++) { + newPtr->numPixels[i] = 0; + } newPtr->parentPtr = nodePtr->parentPtr; newPtr->nextPtr = nodePtr->nextPtr; nodePtr->nextPtr = newPtr; @@ -3347,11 +4039,11 @@ Rebalance(treePtr, nodePtr) newPtr->children.nodePtr = childPtr->nextPtr; childPtr->nextPtr = NULL; } - RecomputeNodeCounts(nodePtr); + RecomputeNodeCounts(treePtr, nodePtr); nodePtr->parentPtr->numChildren++; nodePtr = newPtr; if (nodePtr->numChildren <= MAX_CHILDREN) { - RecomputeNodeCounts(nodePtr); + RecomputeNodeCounts(treePtr, nodePtr); break; } } @@ -3462,7 +4154,7 @@ Rebalance(treePtr, nodePtr) */ if (totalChildren <= MAX_CHILDREN) { - RecomputeNodeCounts(nodePtr); + RecomputeNodeCounts(treePtr, nodePtr); nodePtr->nextPtr = otherPtr->nextPtr; nodePtr->parentPtr->numChildren--; DeleteSummaries(otherPtr->summaryPtr); @@ -3482,8 +4174,8 @@ Rebalance(treePtr, nodePtr) otherPtr->children.nodePtr = halfwayNodePtr->nextPtr; halfwayNodePtr->nextPtr = NULL; } - RecomputeNodeCounts(nodePtr); - RecomputeNodeCounts(otherPtr); + RecomputeNodeCounts(treePtr, nodePtr); + RecomputeNodeCounts(treePtr, otherPtr); } } } @@ -3511,7 +4203,8 @@ Rebalance(treePtr, nodePtr) */ static void -RecomputeNodeCounts(nodePtr) +RecomputeNodeCounts(treePtr, nodePtr) + register BTree *treePtr; /* The whole B-tree */ register Node *nodePtr; /* Node whose tag summary information * must be recomputed. */ { @@ -3520,7 +4213,8 @@ RecomputeNodeCounts(nodePtr) register TkTextLine *linePtr; register TkTextSegment *segPtr; TkTextTag *tagPtr; - + int ref; + /* * Zero out all the existing counts for the node, but don't delete * the existing Summary records (most of them will probably be reused). @@ -3532,7 +4226,9 @@ RecomputeNodeCounts(nodePtr) } nodePtr->numChildren = 0; nodePtr->numLines = 0; - nodePtr->numPixels = 0; + for (ref = 0; ref<treePtr->pixelReferences; ref++) { + nodePtr->numPixels[ref] = 0; + } /* * Scan through the children, adding the childrens' tag counts into @@ -3545,7 +4241,9 @@ RecomputeNodeCounts(nodePtr) linePtr = linePtr->nextPtr) { nodePtr->numChildren++; nodePtr->numLines++; - nodePtr->numPixels += linePtr->pixelHeight; + for (ref = 0; ref<treePtr->pixelReferences; ref++) { + nodePtr->numPixels[ref] += linePtr->pixels[2*ref]; + } linePtr->parentPtr = nodePtr; for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { @@ -3577,7 +4275,9 @@ RecomputeNodeCounts(nodePtr) childPtr = childPtr->nextPtr) { nodePtr->numChildren++; nodePtr->numLines += childPtr->numLines; - nodePtr->numPixels += childPtr->numPixels; + for (ref = 0; ref<treePtr->pixelReferences; ref++) { + nodePtr->numPixels[ref] += childPtr->numPixels[ref]; + } childPtr->parentPtr = nodePtr; for (summaryPtr2 = childPtr->summaryPtr; summaryPtr2 != NULL; summaryPtr2 = summaryPtr2->nextPtr) { @@ -3646,7 +4346,7 @@ RecomputeNodeCounts(nodePtr) * * TkBTreeNumLines -- * - * This procedure returns a count of the number of lines of + * This procedure returns a count of the number of logical lines of * text present in a given B-tree. * * Results: @@ -3661,11 +4361,24 @@ RecomputeNodeCounts(nodePtr) */ int -TkBTreeNumLines(tree) +TkBTreeNumLines(tree, textPtr) TkTextBTree tree; /* Information about tree. */ + CONST TkText *textPtr; /* Relative to this client of the + * B-tree */ { BTree *treePtr = (BTree *) tree; - return treePtr->rootPtr->numLines - 1; + int count; + + if (textPtr != NULL && textPtr->end != NULL) { + count = TkBTreeLinesTo(NULL, textPtr->end); + } else { + count = treePtr->rootPtr->numLines - 1; + } + if (textPtr != NULL && textPtr->start != NULL) { + count -= TkBTreeLinesTo(NULL, textPtr->start); + } + + return count; } /* @@ -3674,13 +4387,14 @@ TkBTreeNumLines(tree) * TkBTreeNumPixels -- * * This procedure returns a count of the number of pixels of - * text present in a given B-tree. + * text present in a given widget's B-tree representation. * * Results: * The return value is a count of the number of usable pixels in - * tree (since the dummy line used to mark the end of the tree is - * maintained with zero height, it doesn't feature in this - * calculation). + * tree (since the dummy line used to mark the end of the B-tree is + * maintained with zero height, as are any lines that are before or + * after the '-start -end' range of the text widget in question, + * the number stored at the root is the number we want). * * Side effects: * None. @@ -3689,11 +4403,13 @@ TkBTreeNumLines(tree) */ int -TkBTreeNumPixels(tree) - TkTextBTree tree; /* Information about tree. */ +TkBTreeNumPixels(tree, textPtr) + TkTextBTree tree; /* The B-tree */ + CONST TkText *textPtr; /* Relative to this client of the + * B-tree */ { BTree *treePtr = (BTree *) tree; - return treePtr->rootPtr->numPixels; + return treePtr->rootPtr->numPixels[textPtr->pixelReference]; } /* @@ -4056,54 +4772,3 @@ ToggleCheckProc(segPtr, linePtr) } } } - -/* - *---------------------------------------------------------------------- - * - * TkBTreeCharsInLine -- - * - * This procedure returns a count of the number of characters - * in a given line. - * - * Results: - * The return value is the character count for linePtr. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -int -TkBTreeCharsInLine(linePtr) - TkTextLine *linePtr; /* Line whose characters should be - * counted. */ -{ - TkTextSegment *segPtr; - int count; - - count = 0; - for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { - if (segPtr->typePtr == &tkTextCharType) { - count += Tcl_NumUtfChars(segPtr->body.chars, segPtr->size); - } else { - count += segPtr->size; - } - } - return count; -} - -int -TkBTreeBytesInLine(linePtr) - TkTextLine *linePtr; /* Line whose characters should be - * counted. */ -{ - TkTextSegment *segPtr; - int count; - - count = 0; - for (segPtr = linePtr->segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { - count += segPtr->size; - } - return count; -} |