OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / tk8.6.4 / generic / tkTextDisp.c
diff --git a/util/src/TclTk/tk8.6.4/generic/tkTextDisp.c b/util/src/TclTk/tk8.6.4/generic/tkTextDisp.c
deleted file mode 100644 (file)
index 01ec22d..0000000
+++ /dev/null
@@ -1,8753 +0,0 @@
-/*
- * tkTextDisp.c --
- *
- *     This module provides facilities to display text widgets. It is the
- *     only place where information is kept about the screen layout of text
- *     widgets. (Well, strictly, each TkTextLine and B-tree node caches its
- *     last observed pixel height, but that information originates here).
- *
- * Copyright (c) 1992-1994 The Regents of the University of California.
- * Copyright (c) 1994-1997 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-
-#include "tkInt.h"
-#include "tkText.h"
-
-#ifdef _WIN32
-#include "tkWinInt.h"
-#elif defined(__CYGWIN__)
-#include "tkUnixInt.h"
-#endif
-
-#ifdef MAC_OSX_TK
-#include "tkMacOSXInt.h"
-#endif
-
-/*
- * "Calculations of line pixel heights and the size of the vertical
- * scrollbar."
- *
- * Given that tag, font and elide changes can happen to large numbers of
- * diverse chunks in a text widget containing megabytes of text, it is not
- * possible to recalculate all affected height information immediately any
- * such change takes place and maintain a responsive user-experience. Yet, for
- * an accurate vertical scrollbar to be drawn, we must know the total number
- * of vertical pixels shown on display versus the number available to be
- * displayed.
- *
- * The way the text widget solves this problem is by maintaining cached line
- * pixel heights (in the BTree for each logical line), and having asynchronous
- * timer callbacks (i) to iterate through the logical lines recalculating
- * their heights, and (ii) to recalculate the vertical scrollbar's position
- * and size.
- *
- * Typically this works well but there are some situations where the overall
- * functional design of this file causes some problems. These problems can
- * only arise because the calculations used to display lines on screen are not
- * connected to those in the iterating-line- recalculation-process.
- *
- * The reason for this disconnect is that the display calculations operate in
- * display lines, and the iteration and cache operates in logical lines.
- * Given that the display calculations both need not contain complete logical
- * lines (at top or bottom of display), and that they do not actually keep
- * track of logical lines (for simplicity of code and historical design), this
- * means a line may be known and drawn with a different pixel height to that
- * which is cached in the BTree, and this might cause some temporary
- * undesirable mismatch between display and the vertical scrollbar.
- *
- * All such mismatches should be temporary, however, since the asynchronous
- * height calculations will always catch up eventually.
- *
- * For further details see the comments before and within the following
- * functions below: LayoutDLine, AsyncUpdateLineMetrics, GetYView,
- * GetYPixelCount, TkTextUpdateOneLine, TkTextUpdateLineMetrics.
- *
- * For details of the way in which the BTree keeps track of pixel heights, see
- * tkTextBTree.c. Basically the BTree maintains two pieces of information: the
- * logical line indices and the pixel height cache.
- */
-
-/*
- * TK_LAYOUT_WITH_BASE_CHUNKS:
- *
- *     With this macro set, collect all char chunks that have no holes
- *     between them, that are on the same line and use the same font and font
- *     size. Allocate the chars of all these chunks, the so-called "stretch",
- *     in a DString in the first chunk, the so-called "base chunk". Use the
- *     base chunk string for measuring and drawing, so that these actions are
- *     always performed with maximum context.
- *
- *     This is necessary for text rendering engines that provide ligatures
- *     and sub-pixel layout, like ATSU on Mac. If we don't do this, the
- *     measuring will change all the time, leading to an ugly "tremble and
- *     shiver" effect. This is because of the continuous splitting and
- *     re-merging of chunks that goes on in a text widget, when the cursor or
- *     the selection move.
- *
- * Side effects:
- *
- *     Memory management changes. Instead of attaching the character data to
- *     the clientData structures of the char chunks, an additional DString is
- *     used. The collection process will even lead to resizing this DString
- *     for large stretches (> TCL_DSTRING_STATIC_SIZE == 200). We could
- *     reduce the overall memory footprint by copying the result to a plain
- *     char array after the line breaking process, but that would complicate
- *     the code and make performance even worse speedwise. See also TODOs.
- *
- * TODOs:
- *
- *    -        Move the character collection process from the LayoutProc into
- *     LayoutDLine(), so that the collection can be done before actual
- *     layout. In this way measuring can look at the following text, too,
- *     right from the beginning. Memory handling can also be improved with
- *     this. Problem: We don't easily know which chunks are adjacent until
- *     all the other chunks have calculated their width. Apparently marks
- *     would return width==0. A separate char collection loop would have to
- *     know these things.
- *
- *    -        Use a new context parameter to pass the context from LayoutDLine() to
- *     the LayoutProc instead of using a global variable like now. Not
- *     pressing until the previous point gets implemented.
- */
-
-/*
- * The following structure describes how to display a range of characters.
- * The information is generated by scanning all of the tags associated with
- * the characters and combining that with default information for the overall
- * widget. These structures form the hash keys for dInfoPtr->styleTable.
- */
-
-typedef struct StyleValues {
-    Tk_3DBorder border;                /* Used for drawing background under text.
-                                * NULL means use widget background. */
-    int borderWidth;           /* Width of 3-D border for background. */
-    int relief;                        /* 3-D relief for background. */
-    Pixmap bgStipple;          /* Stipple bitmap for background. None means
-                                * draw solid. */
-    XColor *fgColor;           /* Foreground color for text. */
-    Tk_Font tkfont;            /* Font for displaying text. */
-    Pixmap fgStipple;          /* Stipple bitmap for text and other
-                                * foreground stuff. None means draw solid.*/
-    int justify;               /* Justification style for text. */
-    int lMargin1;              /* Left margin, in pixels, for first display
-                                * line of each text line. */
-    int lMargin2;              /* Left margin, in pixels, for second and
-                                * later display lines of each text line. */
-    int offset;                        /* Offset in pixels of baseline, relative to
-                                * baseline of line. */
-    int overstrike;            /* Non-zero means draw overstrike through
-                                * text. */
-    int rMargin;               /* Right margin, in pixels. */
-    int spacing1;              /* Spacing above first dline in text line. */
-    int spacing2;              /* Spacing between lines of dline. */
-    int spacing3;              /* Spacing below last dline in text line. */
-    TkTextTabArray *tabArrayPtr;/* Locations and types of tab stops (may be
-                                * NULL). */
-    int tabStyle;              /* One of TABULAR or WORDPROCESSOR. */
-    int underline;             /* Non-zero means draw underline underneath
-                                * text. */
-    int elide;                 /* Zero means draw text, otherwise not. */
-    TkWrapMode wrapMode;       /* How to handle wrap-around for this tag.
-                                * One of TEXT_WRAPMODE_CHAR,
-                                * TEXT_WRAPMODE_NONE or TEXT_WRAPMODE_WORD.*/
-} StyleValues;
-
-/*
- * The following structure extends the StyleValues structure above with
- * graphics contexts used to actually draw the characters. The entries in
- * dInfoPtr->styleTable point to structures of this type.
- */
-
-typedef struct TextStyle {
-    int refCount;              /* Number of times this structure is
-                                * referenced in Chunks. */
-    GC bgGC;                   /* Graphics context for background. None means
-                                * use widget background. */
-    GC fgGC;                   /* Graphics context for foreground. */
-    StyleValues *sValuePtr;    /* Raw information from which GCs were
-                                * derived. */
-    Tcl_HashEntry *hPtr;       /* Pointer to entry in styleTable. Used to
-                                * delete entry. */
-} TextStyle;
-
-/*
- * The following macro determines whether two styles have the same background
- * so that, for example, no beveled border should be drawn between them.
- */
-
-#define SAME_BACKGROUND(s1, s2) \
-    (((s1)->sValuePtr->border == (s2)->sValuePtr->border) \
-       && ((s1)->sValuePtr->borderWidth == (s2)->sValuePtr->borderWidth) \
-       && ((s1)->sValuePtr->relief == (s2)->sValuePtr->relief) \
-       && ((s1)->sValuePtr->bgStipple == (s2)->sValuePtr->bgStipple))
-
-/*
- * The following macro is used to compare two floating-point numbers to within
- * a certain degree of scale. Direct comparison fails on processors where the
- * processor and memory representations of FP numbers of a particular
- * precision is different (e.g. Intel)
- */
-
-#define FP_EQUAL_SCALE(double1, double2, scaleFactor) \
-    (fabs((double1)-(double2))*((scaleFactor)+1.0) < 0.3)
-
-/*
- * Macro to make debugging/testing logging a little easier.
- */
-
-#define LOG(toVar,what) \
-    Tcl_SetVar2(textPtr->interp, toVar, NULL, (what), \
-           TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT)
-
-/*
- * The following structure describes one line of the display, which may be
- * either part or all of one line of the text.
- */
-
-typedef struct DLine {
-    TkTextIndex index;         /* Identifies first character in text that is
-                                * displayed on this line. */
-    int byteCount;             /* Number of bytes accounted for by this
-                                * display line, including a trailing space or
-                                * newline that isn't actually displayed. */
-    int logicalLinesMerged;    /* Number of extra logical lines merged into
-                                * this one due to elided newlines. */
-    int y;                     /* Y-position at which line is supposed to be
-                                * drawn (topmost pixel of rectangular area
-                                * occupied by line). */
-    int oldY;                  /* Y-position at which line currently appears
-                                * on display. This is used to move lines by
-                                * scrolling rather than re-drawing. If
-                                * 'flags' have the OLD_Y_INVALID bit set,
-                                * then we will never examine this field
-                                * (which means line isn't currently visible
-                                * on display and must be redrawn). */
-    int height;                        /* Height of line, in pixels. */
-    int baseline;              /* Offset of text baseline from y, in
-                                * pixels. */
-    int spaceAbove;            /* How much extra space was added to the top
-                                * of the line because of spacing options.
-                                * This is included in height and baseline. */
-    int spaceBelow;            /* How much extra space was added to the
-                                * bottom of the line because of spacing
-                                * options. This is included in height. */
-    int length;                        /* Total length of line, in pixels. */
-    TkTextDispChunk *chunkPtr; /* Pointer to first chunk in list of all of
-                                * those that are displayed on this line of
-                                * the screen. */
-    struct DLine *nextPtr;     /* Next in list of all display lines for this
-                                * window. The list is sorted in order from
-                                * top to bottom. Note: the next DLine doesn't
-                                * always correspond to the next line of text:
-                                * (a) can have multiple DLines for one text
-                                * line (wrapping), (b) can have elided newlines,
-                                * and (c) can have gaps where DLine's
-                                * have been deleted because they're out of
-                                * date. */
-    int flags;                 /* Various flag bits: see below for values. */
-} DLine;
-
-/*
- * Flag bits for DLine structures:
- *
- * HAS_3D_BORDER -             Non-zero means that at least one of the chunks
- *                             in this line has a 3D border, so it
- *                             potentially interacts with 3D borders in
- *                             neighboring lines (see DisplayLineBackground).
- * NEW_LAYOUT -                        Non-zero means that the line has been
- *                             re-layed out since the last time the display
- *                             was updated.
- * TOP_LINE -                  Non-zero means that this was the top line in
- *                             in the window the last time that the window
- *                             was laid out. This is important because a line
- *                             may be displayed differently if its at the top
- *                             or bottom than if it's in the middle
- *                             (e.g. beveled edges aren't displayed for
- *                             middle lines if the adjacent line has a
- *                             similar background).
- * BOTTOM_LINE -               Non-zero means that this was the bottom line
- *                             in the window the last time that the window
- *                             was laid out.
- * OLD_Y_INVALID -             The value of oldY in the structure is not
- *                             valid or useful and should not be examined.
- *                             'oldY' is only useful when the DLine is
- *                             currently displayed at a different position
- *                             and we wish to re-display it via scrolling, so
- *                             this means the DLine needs redrawing.
- */
-
-#define HAS_3D_BORDER  1
-#define NEW_LAYOUT     2
-#define TOP_LINE       4
-#define BOTTOM_LINE    8
-#define OLD_Y_INVALID  16
-
-/*
- * Overall display information for a text widget:
- */
-
-typedef struct TextDInfo {
-    Tcl_HashTable styleTable;  /* Hash table that maps from StyleValues to
-                                * TextStyles for this widget. */
-    DLine *dLinePtr;           /* First in list of all display lines for this
-                                * widget, in order from top to bottom. */
-    int topPixelOffset;                /* Identifies first pixel in top display line
-                                * to display in window. */
-    int newTopPixelOffset;     /* Desired first pixel in top display line to
-                                * display in window. */
-    GC copyGC;                 /* Graphics context for copying from off-
-                                * screen pixmaps onto screen. */
-    GC scrollGC;               /* Graphics context for copying from one place
-                                * in the window to another (scrolling):
-                                * differs from copyGC in that we need to get
-                                * GraphicsExpose events. */
-    int x;                     /* First x-coordinate that may be used for
-                                * actually displaying line information.
-                                * Leaves space for border, etc. */
-    int y;                     /* First y-coordinate that may be used for
-                                * actually displaying line information.
-                                * Leaves space for border, etc. */
-    int maxX;                  /* First x-coordinate to right of available
-                                * space for displaying lines. */
-    int maxY;                  /* First y-coordinate below available space
-                                * for displaying lines. */
-    int topOfEof;              /* Top-most pixel (lowest y-value) that has
-                                * been drawn in the appropriate fashion for
-                                * the portion of the window after the last
-                                * line of the text. This field is used to
-                                * figure out when to redraw part or all of
-                                * the eof field. */
-
-    /*
-     * Information used for scrolling:
-     */
-
-    int newXPixelOffset;       /* Desired x scroll position, measured as the
-                                * number of pixels off-screen to the left for
-                                * a line with no left margin. */
-    int curXPixelOffset;       /* Actual x scroll position, measured as the
-                                * number of pixels off-screen to the left. */
-    int maxLength;             /* Length in pixels of longest line that's
-                                * visible in window (length may exceed window
-                                * size). If there's no wrapping, this will be
-                                * zero. */
-    double xScrollFirst, xScrollLast;
-                               /* Most recent values reported to horizontal
-                                * scrollbar; used to eliminate unnecessary
-                                * reports. */
-    double yScrollFirst, yScrollLast;
-                               /* Most recent values reported to vertical
-                                * scrollbar; used to eliminate unnecessary
-                                * reports. */
-
-    /*
-     * The following information is used to implement scanning:
-     */
-
-    int scanMarkXPixel;                /* Pixel index of left edge of the window when
-                                * the scan started. */
-    int scanMarkX;             /* X-position of mouse at time scan started. */
-    int scanTotalYScroll;      /* Total scrolling (in screen pixels) that has
-                                * occurred since scanMarkY was set. */
-    int scanMarkY;             /* Y-position of mouse at time scan started. */
-
-    /*
-     * Miscellaneous information:
-     */
-
-    int dLinesInvalidated;     /* This value is set to 1 whenever something
-                                * happens that invalidates information in
-                                * DLine structures; if a redisplay is in
-                                * progress, it will see this and abort the
-                                * redisplay. This is needed because, for
-                                * example, an embedded window could change
-                                * its size when it is first displayed,
-                                * invalidating the DLine that is currently
-                                * being displayed. If redisplay continues, it
-                                * will use freed memory and could dump
-                                * core. */
-    int flags;                 /* Various flag values: see below for
-                                * definitions. */
-    /*
-     * Information used to handle the asynchronous updating of the y-scrollbar
-     * and the vertical height calculations:
-     */
-
-    int lineMetricUpdateEpoch; /* Stores a number which is incremented each
-                                * time the text widget changes in a
-                                * significant way (e.g. resizing or
-                                * geometry-influencing tag changes). */
-    int currentMetricUpdateLine;/* Stores a counter which is used to iterate
-                                * over the logical lines contained in the
-                                * widget and update their geometry
-                                * calculations, if they are out of date. */
-    TkTextIndex metricIndex;   /* If the current metric update line wraps
-                                * into very many display lines, then this is
-                                * used to keep track of what index we've got
-                                * to so far... */
-    int metricPixelHeight;     /* ...and this is for the height calculation
-                                * so far...*/
-    int metricEpoch;           /* ...and this for the epoch of the partial
-                                * calculation so it can be cancelled if
-                                * things change once more. This field will be
-                                * -1 if there is no long-line calculation in
-                                * progress, and take a non-negative value if
-                                * there is such a calculation in progress. */
-    int lastMetricUpdateLine;  /* When the current update line reaches this
-                                * line, we are done and should stop the
-                                * asychronous callback mechanism. */
-    Tcl_TimerToken lineUpdateTimer;
-                               /* A token pointing to the current line metric
-                                * update callback. */
-    Tcl_TimerToken scrollbarTimer;
-                               /* A token pointing to the current scrollbar
-                                * update callback. */
-} TextDInfo;
-
-/*
- * In TkTextDispChunk structures for character segments, the clientData field
- * points to one of the following structures:
- */
-
-#if !TK_LAYOUT_WITH_BASE_CHUNKS
-
-typedef struct CharInfo {
-    int numBytes;              /* Number of bytes to display. */
-    char chars[1];             /* UTF characters to display. Actual size will
-                                * be numBytes, not 1. THIS MUST BE THE LAST
-                                * FIELD IN THE STRUCTURE. */
-} CharInfo;
-
-#else /* TK_LAYOUT_WITH_BASE_CHUNKS */
-
-typedef struct CharInfo {
-    TkTextDispChunk *baseChunkPtr;
-    int baseOffset;            /* Starting offset in base chunk
-                                * baseChars. */
-    int numBytes;              /* Number of bytes that belong to this
-                                * chunk. */
-    const char *chars;         /* UTF characters to display. Actually points
-                                * into the baseChars of the base chunk. Only
-                                * valid after FinalizeBaseChunk(). */
-} CharInfo;
-
-/*
- * The BaseCharInfo is a CharInfo with some additional data added.
- */
-
-typedef struct BaseCharInfo {
-    CharInfo ci;
-    Tcl_DString baseChars;     /* Actual characters for the stretch of text
-                                * represented by this base chunk. */
-    int width;                 /* Width in pixels of the whole string, if
-                                * known, else -1. Valid during
-                                * LayoutDLine(). */
-} BaseCharInfo;
-
-/* TODO: Thread safety */
-static TkTextDispChunk *baseCharChunkPtr = NULL;
-
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-
-/*
- * Flag values for TextDInfo structures:
- *
- * DINFO_OUT_OF_DATE:          Non-zero means that the DLine structures for
- *                             this window are partially or completely out of
- *                             date and need to be recomputed.
- * REDRAW_PENDING:             Means that a when-idle handler has been
- *                             scheduled to update the display.
- * REDRAW_BORDERS:             Means window border or pad area has
- *                             potentially been damaged and must be redrawn.
- * REPICK_NEEDED:              1 means that the widget has been modified in a
- *                             way that could change the current character (a
- *                             different character might be under the mouse
- *                             cursor now). Need to recompute the current
- *                             character before the next redisplay.
- */
-
-#define DINFO_OUT_OF_DATE      1
-#define REDRAW_PENDING         2
-#define REDRAW_BORDERS         4
-#define REPICK_NEEDED          8
-
-/*
- * Action values for FreeDLines:
- *
- * DLINE_FREE:         Free the lines, but no need to unlink them from the
- *                     current list of actual display lines.
- * DLINE_UNLINK:       Free and unlink from current display.
- * DLINE_FREE_TEMP:    Free, but don't unlink, and also don't set
- *                     'dLinesInvalidated'.
- */
-
-#define DLINE_FREE       0
-#define DLINE_UNLINK     1
-#define DLINE_FREE_TEMP          2
-
-/*
- * The following counters keep statistics about redisplay that can be checked
- * to see how clever this code is at reducing redisplays.
- */
-
-static int numRedisplays;      /* Number of calls to DisplayText. */
-static int linesRedrawn;       /* Number of calls to DisplayDLine. */
-static int numCopies;          /* Number of calls to XCopyArea to copy part
-                                * of the screen. */
-static int lineHeightsRecalculated;
-                               /* Number of line layouts purely for height
-                                * calculation purposes.*/
-/*
- * Forward declarations for functions defined later in this file:
- */
-
-static void            AdjustForTab(TkText *textPtr,
-                           TkTextTabArray *tabArrayPtr, int index,
-                           TkTextDispChunk *chunkPtr);
-static void            CharBboxProc(TkText *textPtr,
-                           TkTextDispChunk *chunkPtr, int index, int y,
-                           int lineHeight, int baseline, int *xPtr,
-                           int *yPtr, int *widthPtr, int *heightPtr);
-static int             CharChunkMeasureChars(TkTextDispChunk *chunkPtr,
-                           const char *chars, int charsLen,
-                           int start, int end, int startX, int maxX,
-                           int flags, int *nextX);
-static void            CharDisplayProc(TkText *textPtr,
-                           TkTextDispChunk *chunkPtr, int x, int y,
-                           int height, int baseline, Display *display,
-                           Drawable dst, int screenY);
-static int             CharMeasureProc(TkTextDispChunk *chunkPtr, int x);
-static void            CharUndisplayProc(TkText *textPtr,
-                           TkTextDispChunk *chunkPtr);
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-static void            FinalizeBaseChunk(TkTextDispChunk *additionalChunkPtr);
-static void            FreeBaseChunk(TkTextDispChunk *baseChunkPtr);
-static int             IsSameFGStyle(TextStyle *style1, TextStyle *style2);
-static void            RemoveFromBaseChunk(TkTextDispChunk *chunkPtr);
-#endif
-/*
- * Definitions of elided procs. Compiler can't inline these since we use
- * pointers to these functions. ElideDisplayProc and ElideUndisplayProc are
- * special-cased for speed, as potentially many elided DLine chunks if large,
- * tag toggle-filled elided region.
- */
-static void            ElideBboxProc(TkText *textPtr,
-                           TkTextDispChunk *chunkPtr, int index, int y,
-                           int lineHeight, int baseline, int *xPtr,
-                           int *yPtr, int *widthPtr, int *heightPtr);
-static int             ElideMeasureProc(TkTextDispChunk *chunkPtr, int x);
-static void            DisplayDLine(TkText *textPtr, DLine *dlPtr,
-                           DLine *prevPtr, Pixmap pixmap);
-static void            DisplayLineBackground(TkText *textPtr, DLine *dlPtr,
-                           DLine *prevPtr, Pixmap pixmap);
-static void            DisplayText(ClientData clientData);
-static DLine *         FindDLine(TkText *textPtr, DLine *dlPtr,
-                            const TkTextIndex *indexPtr);
-static void            FreeDLines(TkText *textPtr, DLine *firstPtr,
-                           DLine *lastPtr, int action);
-static void            FreeStyle(TkText *textPtr, TextStyle *stylePtr);
-static TextStyle *     GetStyle(TkText *textPtr, const TkTextIndex *indexPtr);
-static void            GetXView(Tcl_Interp *interp, TkText *textPtr,
-                           int report);
-static void            GetYView(Tcl_Interp *interp, TkText *textPtr,
-                           int report);
-static int             GetYPixelCount(TkText *textPtr, DLine *dlPtr);
-static DLine *         LayoutDLine(TkText *textPtr,
-                           const TkTextIndex *indexPtr);
-static int             MeasureChars(Tk_Font tkfont, const char *source,
-                           int maxBytes, int rangeStart, int rangeLength,
-                           int startX, int maxX, int flags, int *nextXPtr);
-static void            MeasureUp(TkText *textPtr,
-                           const TkTextIndex *srcPtr, int distance,
-                           TkTextIndex *dstPtr, int *overlap);
-static int             NextTabStop(Tk_Font tkfont, int x, int tabOrigin);
-static void            UpdateDisplayInfo(TkText *textPtr);
-static void            YScrollByLines(TkText *textPtr, int offset);
-static void            YScrollByPixels(TkText *textPtr, int offset);
-static int             SizeOfTab(TkText *textPtr, int tabStyle,
-                           TkTextTabArray *tabArrayPtr, int *indexPtr, int x,
-                           int maxX);
-static void            TextChanged(TkText *textPtr,
-                           const TkTextIndex *index1Ptr,
-                           const TkTextIndex *index2Ptr);
-static void            TextInvalidateRegion(TkText *textPtr, TkRegion region);
-static void            TextRedrawTag(TkText *textPtr,
-                           TkTextIndex *index1Ptr, TkTextIndex *index2Ptr,
-                           TkTextTag *tagPtr, int withTag);
-static void            TextInvalidateLineMetrics(TkText *textPtr,
-                           TkTextLine *linePtr, int lineCount, int action);
-static int             CalculateDisplayLineHeight(TkText *textPtr,
-                           const TkTextIndex *indexPtr, int *byteCountPtr,
-                           int *mergedLinePtr);
-static void            DlineIndexOfX(TkText *textPtr,
-                           DLine *dlPtr, int x, TkTextIndex *indexPtr);
-static int             DlineXOfIndex(TkText *textPtr,
-                           DLine *dlPtr, int byteIndex);
-static int             TextGetScrollInfoObj(Tcl_Interp *interp,
-                           TkText *textPtr, int objc,
-                           Tcl_Obj *const objv[], double *dblPtr,
-                           int *intPtr);
-static void            AsyncUpdateLineMetrics(ClientData clientData);
-static void            AsyncUpdateYScrollbar(ClientData clientData);
-static int              IsStartOfNotMergedLine(TkText *textPtr,
-                            CONST TkTextIndex *indexPtr);
-
-/*
- * Result values returned by TextGetScrollInfoObj:
- */
-
-#define TKTEXT_SCROLL_MOVETO   1
-#define TKTEXT_SCROLL_PAGES    2
-#define TKTEXT_SCROLL_UNITS    3
-#define TKTEXT_SCROLL_ERROR    4
-#define TKTEXT_SCROLL_PIXELS   5
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextCreateDInfo --
- *
- *     This function is called when a new text widget is created. Its job is
- *     to set up display-related information for the widget.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     A TextDInfo data structure is allocated and initialized and attached
- *     to textPtr.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextCreateDInfo(
-    TkText *textPtr)           /* Overall information for text widget. */
-{
-    register TextDInfo *dInfoPtr;
-    XGCValues gcValues;
-
-    dInfoPtr = ckalloc(sizeof(TextDInfo));
-    Tcl_InitHashTable(&dInfoPtr->styleTable, sizeof(StyleValues)/sizeof(int));
-    dInfoPtr->dLinePtr = NULL;
-    dInfoPtr->copyGC = None;
-    gcValues.graphics_exposures = True;
-    dInfoPtr->scrollGC = Tk_GetGC(textPtr->tkwin, GCGraphicsExposures,
-           &gcValues);
-    dInfoPtr->topOfEof = 0;
-    dInfoPtr->newXPixelOffset = 0;
-    dInfoPtr->curXPixelOffset = 0;
-    dInfoPtr->maxLength = 0;
-    dInfoPtr->xScrollFirst = -1;
-    dInfoPtr->xScrollLast = -1;
-    dInfoPtr->yScrollFirst = -1;
-    dInfoPtr->yScrollLast = -1;
-    dInfoPtr->scanMarkXPixel = 0;
-    dInfoPtr->scanMarkX = 0;
-    dInfoPtr->scanTotalYScroll = 0;
-    dInfoPtr->scanMarkY = 0;
-    dInfoPtr->dLinesInvalidated = 0;
-    dInfoPtr->flags = DINFO_OUT_OF_DATE;
-    dInfoPtr->topPixelOffset = 0;
-    dInfoPtr->newTopPixelOffset = 0;
-    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,
-           AsyncUpdateLineMetrics, textPtr);
-    textPtr->refCount++;
-    dInfoPtr->scrollbarTimer = Tcl_CreateTimerHandler(200,
-           AsyncUpdateYScrollbar, textPtr);
-
-    textPtr->dInfoPtr = dInfoPtr;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextFreeDInfo --
- *
- *     This function is called to free up all of the private display
- *     information kept by this file for a text widget.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Lots of resources get freed.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextFreeDInfo(
-    TkText *textPtr)           /* Overall information for text widget. */
-{
-    register TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-
-    /*
-     * Be careful to free up styleTable *after* freeing up all the DLines, so
-     * that the hash table is still intact to free up the style-related
-     * information from the lines. Once the lines are all free then styleTable
-     * will be empty.
-     */
-
-    FreeDLines(textPtr, dInfoPtr->dLinePtr, NULL, DLINE_UNLINK);
-    Tcl_DeleteHashTable(&dInfoPtr->styleTable);
-    if (dInfoPtr->copyGC != None) {
-       Tk_FreeGC(textPtr->display, dInfoPtr->copyGC);
-    }
-    Tk_FreeGC(textPtr->display, dInfoPtr->scrollGC);
-    if (dInfoPtr->flags & REDRAW_PENDING) {
-       Tcl_CancelIdleCall(DisplayText, textPtr);
-    }
-    if (dInfoPtr->lineUpdateTimer != NULL) {
-       Tcl_DeleteTimerHandler(dInfoPtr->lineUpdateTimer);
-       textPtr->refCount--;
-       dInfoPtr->lineUpdateTimer = NULL;
-    }
-    if (dInfoPtr->scrollbarTimer != NULL) {
-       Tcl_DeleteTimerHandler(dInfoPtr->scrollbarTimer);
-       textPtr->refCount--;
-       dInfoPtr->scrollbarTimer = NULL;
-    }
-    ckfree(dInfoPtr);
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * GetStyle --
- *
- *     This function creates all the information needed to display text at a
- *     particular location.
- *
- * Results:
- *     The return value is a pointer to a TextStyle structure that
- *     corresponds to *sValuePtr.
- *
- * Side effects:
- *     A new entry may be created in the style table for the widget.
- *
- *----------------------------------------------------------------------
- */
-
-static TextStyle *
-GetStyle(
-    TkText *textPtr,           /* Overall information about text widget. */
-    const TkTextIndex *indexPtr)/* The character in the text for which display
-                                * information is wanted. */
-{
-    TkTextTag **tagPtrs;
-    register TkTextTag *tagPtr;
-    StyleValues styleValues;
-    TextStyle *stylePtr;
-    Tcl_HashEntry *hPtr;
-    int numTags, isNew, i;
-    XGCValues gcValues;
-    unsigned long mask;
-    /*
-     * The variables below keep track of the highest-priority specification
-     * that has occurred for each of the various fields of the StyleValues.
-     */
-    int borderPrio, borderWidthPrio, reliefPrio, bgStipplePrio;
-    int fgPrio, fontPrio, fgStipplePrio;
-    int underlinePrio, elidePrio, justifyPrio, offsetPrio;
-    int lMargin1Prio, lMargin2Prio, rMarginPrio;
-    int spacing1Prio, spacing2Prio, spacing3Prio;
-    int overstrikePrio, tabPrio, tabStylePrio, wrapPrio;
-
-    /*
-     * Find out what tags are present for the character, then compute a
-     * StyleValues structure corresponding to those tags (scan through all of
-     * the tags, saving information for the highest-priority tag).
-     */
-
-    tagPtrs = TkBTreeGetTags(indexPtr, textPtr, &numTags);
-    borderPrio = borderWidthPrio = reliefPrio = bgStipplePrio = -1;
-    fgPrio = fontPrio = fgStipplePrio = -1;
-    underlinePrio = elidePrio = justifyPrio = offsetPrio = -1;
-    lMargin1Prio = lMargin2Prio = rMarginPrio = -1;
-    spacing1Prio = spacing2Prio = spacing3Prio = -1;
-    overstrikePrio = tabPrio = tabStylePrio = wrapPrio = -1;
-    memset(&styleValues, 0, sizeof(StyleValues));
-    styleValues.relief = TK_RELIEF_FLAT;
-    styleValues.fgColor = textPtr->fgColor;
-    styleValues.tkfont = textPtr->tkfont;
-    styleValues.justify = TK_JUSTIFY_LEFT;
-    styleValues.spacing1 = textPtr->spacing1;
-    styleValues.spacing2 = textPtr->spacing2;
-    styleValues.spacing3 = textPtr->spacing3;
-    styleValues.tabArrayPtr = textPtr->tabArrayPtr;
-    styleValues.tabStyle = textPtr->tabStyle;
-    styleValues.wrapMode = textPtr->wrapMode;
-    styleValues.elide = 0;
-
-    for (i = 0 ; i < numTags; i++) {
-       Tk_3DBorder border;
-
-       tagPtr = tagPtrs[i];
-       border = tagPtr->border;
-
-       /*
-        * If this is the selection tag, and inactiveSelBorder is NULL (the
-        * default on Windows), then we need to skip it if we don't have the
-        * focus.
-        */
-
-       if ((tagPtr == textPtr->selTagPtr) && !(textPtr->flags & GOT_FOCUS)) {
-           if (textPtr->inactiveSelBorder == NULL
-#ifdef MAC_OSX_TK
-                   /* Don't show inactive selection in disabled widgets. */
-                   || textPtr->state == TK_TEXT_STATE_DISABLED
-#endif
-           ) {
-               continue;
-           }
-           border = textPtr->inactiveSelBorder;
-       }
-
-       if ((border != NULL) && (tagPtr->priority > borderPrio)) {
-           styleValues.border = border;
-           borderPrio = tagPtr->priority;
-       }
-       if ((tagPtr->borderWidthPtr != NULL)
-               && (Tcl_GetString(tagPtr->borderWidthPtr)[0] != '\0')
-               && (tagPtr->priority > borderWidthPrio)) {
-           styleValues.borderWidth = tagPtr->borderWidth;
-           borderWidthPrio = tagPtr->priority;
-       }
-       if ((tagPtr->reliefString != NULL)
-               && (tagPtr->priority > reliefPrio)) {
-           if (styleValues.border == NULL) {
-               styleValues.border = textPtr->border;
-           }
-           styleValues.relief = tagPtr->relief;
-           reliefPrio = tagPtr->priority;
-       }
-       if ((tagPtr->bgStipple != None)
-               && (tagPtr->priority > bgStipplePrio)) {
-           styleValues.bgStipple = tagPtr->bgStipple;
-           bgStipplePrio = tagPtr->priority;
-       }
-       if ((tagPtr->fgColor != None) && (tagPtr->priority > fgPrio)) {
-           styleValues.fgColor = tagPtr->fgColor;
-           fgPrio = tagPtr->priority;
-       }
-       if ((tagPtr->tkfont != None) && (tagPtr->priority > fontPrio)) {
-           styleValues.tkfont = tagPtr->tkfont;
-           fontPrio = tagPtr->priority;
-       }
-       if ((tagPtr->fgStipple != None)
-               && (tagPtr->priority > fgStipplePrio)) {
-           styleValues.fgStipple = tagPtr->fgStipple;
-           fgStipplePrio = tagPtr->priority;
-       }
-       if ((tagPtr->justifyString != NULL)
-               && (tagPtr->priority > justifyPrio)) {
-           styleValues.justify = tagPtr->justify;
-           justifyPrio = tagPtr->priority;
-       }
-       if ((tagPtr->lMargin1String != NULL)
-               && (tagPtr->priority > lMargin1Prio)) {
-           styleValues.lMargin1 = tagPtr->lMargin1;
-           lMargin1Prio = tagPtr->priority;
-       }
-       if ((tagPtr->lMargin2String != NULL)
-               && (tagPtr->priority > lMargin2Prio)) {
-           styleValues.lMargin2 = tagPtr->lMargin2;
-           lMargin2Prio = tagPtr->priority;
-       }
-       if ((tagPtr->offsetString != NULL)
-               && (tagPtr->priority > offsetPrio)) {
-           styleValues.offset = tagPtr->offset;
-           offsetPrio = tagPtr->priority;
-       }
-       if ((tagPtr->overstrikeString != NULL)
-               && (tagPtr->priority > overstrikePrio)) {
-           styleValues.overstrike = tagPtr->overstrike;
-           overstrikePrio = tagPtr->priority;
-       }
-       if ((tagPtr->rMarginString != NULL)
-               && (tagPtr->priority > rMarginPrio)) {
-           styleValues.rMargin = tagPtr->rMargin;
-           rMarginPrio = tagPtr->priority;
-       }
-       if ((tagPtr->spacing1String != NULL)
-               && (tagPtr->priority > spacing1Prio)) {
-           styleValues.spacing1 = tagPtr->spacing1;
-           spacing1Prio = tagPtr->priority;
-       }
-       if ((tagPtr->spacing2String != NULL)
-               && (tagPtr->priority > spacing2Prio)) {
-           styleValues.spacing2 = tagPtr->spacing2;
-           spacing2Prio = tagPtr->priority;
-       }
-       if ((tagPtr->spacing3String != NULL)
-               && (tagPtr->priority > spacing3Prio)) {
-           styleValues.spacing3 = tagPtr->spacing3;
-           spacing3Prio = tagPtr->priority;
-       }
-       if ((tagPtr->tabStringPtr != NULL)
-               && (tagPtr->priority > tabPrio)) {
-           styleValues.tabArrayPtr = tagPtr->tabArrayPtr;
-           tabPrio = tagPtr->priority;
-       }
-       if ((tagPtr->tabStyle != TK_TEXT_TABSTYLE_NONE)
-               && (tagPtr->priority > tabStylePrio)) {
-           styleValues.tabStyle = tagPtr->tabStyle;
-           tabStylePrio = tagPtr->priority;
-       }
-       if ((tagPtr->underlineString != NULL)
-               && (tagPtr->priority > underlinePrio)) {
-           styleValues.underline = tagPtr->underline;
-           underlinePrio = tagPtr->priority;
-       }
-       if ((tagPtr->elideString != NULL)
-               && (tagPtr->priority > elidePrio)) {
-           styleValues.elide = tagPtr->elide;
-           elidePrio = tagPtr->priority;
-       }
-       if ((tagPtr->wrapMode != TEXT_WRAPMODE_NULL)
-               && (tagPtr->priority > wrapPrio)) {
-           styleValues.wrapMode = tagPtr->wrapMode;
-           wrapPrio = tagPtr->priority;
-       }
-    }
-    if (tagPtrs != NULL) {
-       ckfree(tagPtrs);
-    }
-
-    /*
-     * Use an existing style if there's one around that matches.
-     */
-
-    hPtr = Tcl_CreateHashEntry(&textPtr->dInfoPtr->styleTable,
-           (char *) &styleValues, &isNew);
-    if (!isNew) {
-       stylePtr = Tcl_GetHashValue(hPtr);
-       stylePtr->refCount++;
-       return stylePtr;
-    }
-
-    /*
-     * No existing style matched. Make a new one.
-     */
-
-    stylePtr = ckalloc(sizeof(TextStyle));
-    stylePtr->refCount = 1;
-    if (styleValues.border != NULL) {
-       gcValues.foreground = Tk_3DBorderColor(styleValues.border)->pixel;
-       mask = GCForeground;
-       if (styleValues.bgStipple != None) {
-           gcValues.stipple = styleValues.bgStipple;
-           gcValues.fill_style = FillStippled;
-           mask |= GCStipple|GCFillStyle;
-       }
-       stylePtr->bgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues);
-    } else {
-       stylePtr->bgGC = None;
-    }
-    mask = GCFont;
-    gcValues.font = Tk_FontId(styleValues.tkfont);
-    mask |= GCForeground;
-    gcValues.foreground = styleValues.fgColor->pixel;
-    if (styleValues.fgStipple != None) {
-       gcValues.stipple = styleValues.fgStipple;
-       gcValues.fill_style = FillStippled;
-       mask |= GCStipple|GCFillStyle;
-    }
-    stylePtr->fgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues);
-    stylePtr->sValuePtr = (StyleValues *)
-           Tcl_GetHashKey(&textPtr->dInfoPtr->styleTable, hPtr);
-    stylePtr->hPtr = hPtr;
-    Tcl_SetHashValue(hPtr, stylePtr);
-    return stylePtr;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * FreeStyle --
- *
- *     This function is called when a TextStyle structure is no longer
- *     needed. It decrements the reference count and frees up the space for
- *     the style structure if the reference count is 0.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The storage and other resources associated with the style are freed up
- *     if no-one's still using it.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-FreeStyle(
-    TkText *textPtr,           /* Information about overall widget. */
-    register TextStyle *stylePtr)
-                               /* Information about style to free. */
-{
-    stylePtr->refCount--;
-    if (stylePtr->refCount == 0) {
-       if (stylePtr->bgGC != None) {
-           Tk_FreeGC(textPtr->display, stylePtr->bgGC);
-       }
-       if (stylePtr->fgGC != None) {
-           Tk_FreeGC(textPtr->display, stylePtr->fgGC);
-       }
-       Tcl_DeleteHashEntry(stylePtr->hPtr);
-       ckfree(stylePtr);
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * LayoutDLine --
- *
- *     This function generates a single DLine structure for a display line
- *     whose leftmost character is given by indexPtr.
- *
- * Results:
- *     The return value is a pointer to a DLine structure describing the
- *     display line. All fields are filled in and correct except for y and
- *     nextPtr.
- *
- * Side effects:
- *     Storage is allocated for the new DLine.
- *
- *     See the comments in 'GetYView' for some thoughts on what the side-
- *     effects of this call (or its callers) should be; the synchronisation
- *     of TkTextLine->pixelHeight with the sum of the results of this
- *     function operating on all display lines within each logical line.
- *     Ideally the code should be refactored to ensure the cached pixel
- *     height is never behind what is known when this function is called
- *     elsewhere.
- *
- *     Unfortunately, this function is currently called from many different
- *     places, not just to layout a display line for actual display, but also
- *     simply to calculate some metric or other of one or more display lines
- *     (typically the height). It would be a good idea to do some profiling
- *     of typical text widget usage and the way in which this is called and
- *     see if some optimization could or should be done.
- *
- *----------------------------------------------------------------------
- */
-
-static DLine *
-LayoutDLine(
-    TkText *textPtr,           /* Overall information about text widget. */
-    const TkTextIndex *indexPtr)/* Beginning of display line. May not
-                                * necessarily point to a character
-                                * segment. */
-{
-    register DLine *dlPtr;     /* New display line. */
-    TkTextSegment *segPtr;     /* Current segment in text. */
-    TkTextDispChunk *lastChunkPtr;
-                               /* Last chunk allocated so far for line. */
-    TkTextDispChunk *chunkPtr; /* Current chunk. */
-    TkTextIndex curIndex;
-    TkTextDispChunk *breakChunkPtr;
-                               /* Chunk containing best word break point, if
-                                * any. */
-    TkTextIndex breakIndex;    /* Index of first character in
-                                * breakChunkPtr. */
-    int breakByteOffset;       /* Byte offset of character within
-                                * breakChunkPtr just to right of best break
-                                * point. */
-    int noCharsYet;            /* Non-zero means that no characters have been
-                                * placed on the line yet. */
-    int paragraphStart;                /* Non-zero means that we are on the first
-                                * line of a paragraph (used to choose between
-                                * lmargin1, lmargin2). */
-    int justify;               /* How to justify line: taken from style for
-                                * the first character in line. */
-    int jIndent;               /* Additional indentation (beyond margins) due
-                                * to justification. */
-    int rMargin;               /* Right margin width for line. */
-    TkWrapMode wrapMode;       /* Wrap mode to use for this line. */
-    int x = 0, maxX = 0;       /* Initializations needed only to stop
-                                * compiler warnings. */
-    int wholeLine;             /* Non-zero means this display line runs to
-                                * the end of the text line. */
-    int tabIndex;              /* Index of the current tab stop. */
-    int gotTab;                        /* Non-zero means the current chunk contains a
-                                * tab. */
-    TkTextDispChunk *tabChunkPtr;
-                               /* Pointer to the chunk containing the
-                                * previous tab stop. */
-    int maxBytes;              /* Maximum number of bytes to include in this
-                                * chunk. */
-    TkTextTabArray *tabArrayPtr;/* Tab stops for line; taken from style for
-                                * the first character on line. */
-    int tabStyle;              /* One of TABULAR or WORDPROCESSOR. */
-    int tabSize;               /* Number of pixels consumed by current tab
-                                * stop. */
-    TkTextDispChunk *lastCharChunkPtr;
-                               /* Pointer to last chunk in display lines with
-                                * numBytes > 0. Used to drop 0-sized chunks
-                                * from the end of the line. */
-    int byteOffset, ascent, descent, code, elide, elidesize;
-    StyleValues *sValuePtr;
-    TkTextElideInfo info;      /* Keep track of elide state. */
-
-    /*
-     * Create and initialize a new DLine structure.
-     */
-
-    dlPtr = ckalloc(sizeof(DLine));
-    dlPtr->index = *indexPtr;
-    dlPtr->byteCount = 0;
-    dlPtr->y = 0;
-    dlPtr->oldY = 0;           /* Only set to avoid compiler warnings. */
-    dlPtr->height = 0;
-    dlPtr->baseline = 0;
-    dlPtr->chunkPtr = NULL;
-    dlPtr->nextPtr = NULL;
-    dlPtr->flags = NEW_LAYOUT | OLD_Y_INVALID;
-    dlPtr->logicalLinesMerged = 0;
-
-    /*
-     * This is not necessarily totally correct, where we have merged logical
-     * lines. Fixing this would require a quite significant overhaul, though,
-     * so currently we make do with this.
-     */
-
-    paragraphStart = (indexPtr->byteIndex == 0);
-
-    /*
-     * Special case entirely elide line as there may be 1000s or more.
-     */
-
-    elide = TkTextIsElided(textPtr, indexPtr, &info);
-    if (elide && indexPtr->byteIndex == 0) {
-       maxBytes = 0;
-       for (segPtr = info.segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) {
-           if (segPtr->size > 0) {
-               if (elide == 0) {
-                   /*
-                    * We toggled a tag and the elide state changed to
-                    * visible, and we have something of non-zero size.
-                    * Therefore we must bail out.
-                    */
-
-                   break;
-               }
-               maxBytes += segPtr->size;
-
-               /*
-                * Reset tag elide priority, since we're on a new character.
-                */
-
-           } else if ((segPtr->typePtr == &tkTextToggleOffType)
-                   || (segPtr->typePtr == &tkTextToggleOnType)) {
-               TkTextTag *tagPtr = segPtr->body.toggle.tagPtr;
-
-               /*
-                * The elide state only changes if this tag is either the
-                * current highest priority tag (and is therefore being
-                * toggled off), or it's a new tag with higher priority.
-                */
-
-               if (tagPtr->elideString != NULL) {
-                   info.tagCnts[tagPtr->priority]++;
-                   if (info.tagCnts[tagPtr->priority] & 1) {
-                       info.tagPtrs[tagPtr->priority] = tagPtr;
-                   }
-                   if (tagPtr->priority >= info.elidePriority) {
-                       if (segPtr->typePtr == &tkTextToggleOffType) {
-                           /*
-                            * If it is being toggled off, and it has an elide
-                            * string, it must actually be the current highest
-                            * priority tag, so this check is redundant:
-                            */
-
-                           if (tagPtr->priority != info.elidePriority) {
-                               Tcl_Panic("Bad tag priority being toggled off");
-                           }
-
-                           /*
-                            * Find previous elide tag, if any (if not then
-                            * elide will be zero, of course).
-                            */
-
-                           elide = 0;
-                           while (--info.elidePriority > 0) {
-                               if (info.tagCnts[info.elidePriority] & 1) {
-                                   elide = info.tagPtrs[info.elidePriority]
-                                           ->elide;
-                                   break;
-                               }
-                           }
-                       } else {
-                           elide = tagPtr->elide;
-                           info.elidePriority = tagPtr->priority;
-                       }
-                   }
-               }
-           }
-       }
-
-       if (elide) {
-           dlPtr->byteCount = maxBytes;
-           dlPtr->spaceAbove = dlPtr->spaceBelow = dlPtr->length = 0;
-           if (dlPtr->index.byteIndex == 0) {
-               /*
-                * Elided state goes from beginning to end of an entire
-                * logical line. This means we can update the line's pixel
-                * height, and bring its pixel calculation up to date.
-                */
-
-               TkBTreeLinePixelEpoch(textPtr, dlPtr->index.linePtr)
-                       = textPtr->dInfoPtr->lineMetricUpdateEpoch;
-
-               if (TkBTreeLinePixelCount(textPtr,dlPtr->index.linePtr) != 0) {
-                   TkBTreeAdjustPixelHeight(textPtr,
-                           dlPtr->index.linePtr, 0, 0);
-               }
-           }
-           TkTextFreeElideInfo(&info);
-           return dlPtr;
-       }
-    }
-    TkTextFreeElideInfo(&info);
-
-    /*
-     * Each iteration of the loop below creates one TkTextDispChunk for the
-     * new display line. The line will always have at least one chunk (for the
-     * newline character at the end, if there's nothing else available).
-     */
-
-    curIndex = *indexPtr;
-    lastChunkPtr = NULL;
-    chunkPtr = NULL;
-    noCharsYet = 1;
-    elide = 0;
-    breakChunkPtr = NULL;
-    breakByteOffset = 0;
-    justify = TK_JUSTIFY_LEFT;
-    tabIndex = -1;
-    tabChunkPtr = NULL;
-    tabArrayPtr = NULL;
-    tabStyle = TK_TEXT_TABSTYLE_TABULAR;
-    rMargin = 0;
-    wrapMode = TEXT_WRAPMODE_CHAR;
-    tabSize = 0;
-    lastCharChunkPtr = NULL;
-
-    /*
-     * Find the first segment to consider for the line. Can't call
-     * TkTextIndexToSeg for this because it won't return a segment with zero
-     * size (such as the insertion cursor's mark).
-     */
-
-  connectNextLogicalLine:
-    byteOffset = curIndex.byteIndex;
-    segPtr = curIndex.linePtr->segPtr;
-    while ((byteOffset > 0) && (byteOffset >= segPtr->size)) {
-       byteOffset -= segPtr->size;
-       segPtr = segPtr->nextPtr;
-
-       if (segPtr == NULL) {
-           /*
-            * Two logical lines merged into one display line through eliding
-            * of a newline.
-            */
-
-           TkTextLine *linePtr = TkBTreeNextLine(NULL, curIndex.linePtr);
-           if (linePtr == NULL) {
-               break;
-           }
-
-           dlPtr->logicalLinesMerged++;
-           curIndex.byteIndex = 0;
-           curIndex.linePtr = linePtr;
-           segPtr = curIndex.linePtr->segPtr;
-       }
-    }
-
-    while (segPtr != NULL) {
-       /*
-        * Every logical line still gets at least one chunk due to
-        * expectations in the rest of the code, but we are able to skip
-        * elided portions of the line quickly.
-        *
-        * If current chunk is elided and last chunk was too, coalese.
-        *
-        * This also means that each logical line which is entirely elided
-        * still gets laid out into a DLine, but with zero height. This isn't
-        * particularly a problem, but it does seem somewhat unnecessary. We
-        * may wish to redesign the code to remove these zero height DLines in
-        * the future.
-        */
-
-       if (elide && (lastChunkPtr != NULL)
-               && (lastChunkPtr->displayProc == NULL /*ElideDisplayProc*/)) {
-           elidesize = segPtr->size - byteOffset;
-           if (elidesize > 0) {
-               curIndex.byteIndex += elidesize;
-               lastChunkPtr->numBytes += elidesize;
-               breakByteOffset = lastChunkPtr->breakIndex
-                       = lastChunkPtr->numBytes;
-
-               /*
-                * If have we have a tag toggle, there is a chance that
-                * invisibility state changed, so bail out.
-                */
-           } else if ((segPtr->typePtr == &tkTextToggleOffType)
-                   || (segPtr->typePtr == &tkTextToggleOnType)) {
-               if (segPtr->body.toggle.tagPtr->elideString != NULL) {
-                   elide = (segPtr->typePtr == &tkTextToggleOffType)
-                           ^ segPtr->body.toggle.tagPtr->elide;
-               }
-           }
-
-           byteOffset = 0;
-           segPtr = segPtr->nextPtr;
-
-           if (segPtr == NULL) {
-               /*
-                * Two logical lines merged into one display line through
-                * eliding of a newline.
-                */
-
-               TkTextLine *linePtr = TkBTreeNextLine(NULL, curIndex.linePtr);
-
-               if (linePtr != NULL) {
-                   dlPtr->logicalLinesMerged++;
-                   curIndex.byteIndex = 0;
-                   curIndex.linePtr = linePtr;
-                   goto connectNextLogicalLine;
-               }
-           }
-
-           /*
-            * Code no longer needed, now that we allow logical lines to merge
-            * into a single display line.
-            *
-           if (segPtr == NULL && chunkPtr != NULL) {
-               ckfree(chunkPtr);
-               chunkPtr = NULL;
-           }
-            */
-
-           continue;
-       }
-
-       if (segPtr->typePtr->layoutProc == NULL) {
-           segPtr = segPtr->nextPtr;
-           byteOffset = 0;
-           continue;
-       }
-       if (chunkPtr == NULL) {
-           chunkPtr = ckalloc(sizeof(TkTextDispChunk));
-           chunkPtr->nextPtr = NULL;
-           chunkPtr->clientData = NULL;
-       }
-       chunkPtr->stylePtr = GetStyle(textPtr, &curIndex);
-       elide = chunkPtr->stylePtr->sValuePtr->elide;
-
-       /*
-        * Save style information such as justification and indentation, up
-        * until the first character is encountered, then retain that
-        * information for the rest of the line.
-        */
-
-       if (!elide && noCharsYet) {
-           tabArrayPtr = chunkPtr->stylePtr->sValuePtr->tabArrayPtr;
-           tabStyle = chunkPtr->stylePtr->sValuePtr->tabStyle;
-           justify = chunkPtr->stylePtr->sValuePtr->justify;
-           rMargin = chunkPtr->stylePtr->sValuePtr->rMargin;
-           wrapMode = chunkPtr->stylePtr->sValuePtr->wrapMode;
-
-           /*
-            * See above - this test may not be entirely correct where we have
-            * partially elided lines (and therefore merged logical lines).
-            * In such a case a byteIndex of zero doesn't necessarily mean the
-            * beginning of a logical line.
-            */
-
-           if (paragraphStart) {
-               /*
-                * Beginning of logical line.
-                */
-
-               x = chunkPtr->stylePtr->sValuePtr->lMargin1;
-           } else {
-               /*
-                * Beginning of display line.
-                */
-
-               x = chunkPtr->stylePtr->sValuePtr->lMargin2;
-           }
-           if (wrapMode == TEXT_WRAPMODE_NONE) {
-               maxX = -1;
-           } else {
-               maxX = textPtr->dInfoPtr->maxX - textPtr->dInfoPtr->x
-                       - rMargin;
-               if (maxX < x) {
-                   maxX = x;
-               }
-           }
-       }
-
-       gotTab = 0;
-       maxBytes = segPtr->size - byteOffset;
-       if (segPtr->typePtr == &tkTextCharType) {
-
-           /*
-            * See if there is a tab in the current chunk; if so, only layout
-            * characters up to (and including) the tab.
-            */
-
-           if (!elide && justify == TK_JUSTIFY_LEFT) {
-               char *p;
-
-               for (p = segPtr->body.chars + byteOffset; *p != 0; p++) {
-                   if (*p == '\t') {
-                       maxBytes = (p + 1 - segPtr->body.chars) - byteOffset;
-                       gotTab = 1;
-                       break;
-                   }
-               }
-           }
-
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-           if (baseCharChunkPtr != NULL) {
-               int expectedX =
-                       ((BaseCharInfo *) baseCharChunkPtr->clientData)->width
-                       + baseCharChunkPtr->x;
-
-               if ((expectedX != x) || !IsSameFGStyle(
-                       baseCharChunkPtr->stylePtr, chunkPtr->stylePtr)) {
-                   FinalizeBaseChunk(NULL);
-               }
-           }
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-       }
-       chunkPtr->x = x;
-       if (elide /*&& maxBytes*/) {
-           /*
-            * Don't free style here, as other code expects to be able to do
-            * that.
-            */
-
-           /* breakByteOffset =*/
-           chunkPtr->breakIndex = chunkPtr->numBytes = maxBytes;
-           chunkPtr->width = 0;
-           chunkPtr->minAscent = chunkPtr->minDescent
-                   = chunkPtr->minHeight = 0;
-
-           /*
-            * Would just like to point to canonical empty chunk.
-            */
-
-           chunkPtr->displayProc = NULL;
-           chunkPtr->undisplayProc = NULL;
-           chunkPtr->measureProc = ElideMeasureProc;
-           chunkPtr->bboxProc = ElideBboxProc;
-
-           code = 1;
-       } else {
-           code = segPtr->typePtr->layoutProc(textPtr, &curIndex, segPtr,
-                   byteOffset, maxX-tabSize, maxBytes, noCharsYet, wrapMode,
-                   chunkPtr);
-       }
-       if (code <= 0) {
-           FreeStyle(textPtr, chunkPtr->stylePtr);
-           if (code < 0) {
-               /*
-                * This segment doesn't wish to display itself (e.g. most
-                * marks).
-                */
-
-               segPtr = segPtr->nextPtr;
-               byteOffset = 0;
-               continue;
-           }
-
-           /*
-            * No characters from this segment fit in the window: this means
-            * we're at the end of the display line.
-            */
-
-           if (chunkPtr != NULL) {
-               ckfree(chunkPtr);
-           }
-           break;
-       }
-
-       /*
-        * We currently say we have some characters (and therefore something
-        * from which to examine tag values for the first character of the
-        * line) even if those characters are actually elided. This behaviour
-        * is not well documented, and it might be more consistent to
-        * completely ignore such elided characters and their tags. To do so
-        * change this to:
-        *
-        * if (!elide && chunkPtr->numBytes > 0).
-        */
-
-       if (!elide && chunkPtr->numBytes > 0) {
-           noCharsYet = 0;
-           lastCharChunkPtr = chunkPtr;
-       }
-       if (lastChunkPtr == NULL) {
-           dlPtr->chunkPtr = chunkPtr;
-       } else {
-           lastChunkPtr->nextPtr = chunkPtr;
-       }
-       lastChunkPtr = chunkPtr;
-       x += chunkPtr->width;
-       if (chunkPtr->breakIndex > 0) {
-           breakByteOffset = chunkPtr->breakIndex;
-           breakIndex = curIndex;
-           breakChunkPtr = chunkPtr;
-       }
-       if (chunkPtr->numBytes != maxBytes) {
-           break;
-       }
-
-       /*
-        * If we're at a new tab, adjust the layout for all the chunks
-        * pertaining to the previous tab. Also adjust the amount of space
-        * left in the line to account for space that will be eaten up by the
-        * tab.
-        */
-
-       if (gotTab) {
-           if (tabIndex >= 0) {
-               AdjustForTab(textPtr, tabArrayPtr, tabIndex, tabChunkPtr);
-               x = chunkPtr->x + chunkPtr->width;
-           }
-           tabChunkPtr = chunkPtr;
-           tabSize = SizeOfTab(textPtr, tabStyle, tabArrayPtr, &tabIndex, x,
-                   maxX);
-           if ((maxX >= 0) && (tabSize >= maxX - x)) {
-               break;
-           }
-       }
-       curIndex.byteIndex += chunkPtr->numBytes;
-       byteOffset += chunkPtr->numBytes;
-       if (byteOffset >= segPtr->size) {
-           byteOffset = 0;
-           segPtr = segPtr->nextPtr;
-           if (elide && segPtr == NULL) {
-               /*
-                * An elided section started on this line, and carries on
-                * until the newline. Hence the newline is actually elided,
-                * and we want to merge the display of the next logical line
-                * with this one.
-                */
-
-               TkTextLine *linePtr = TkBTreeNextLine(NULL, curIndex.linePtr);
-
-               if (linePtr != NULL) {
-                   dlPtr->logicalLinesMerged++;
-                   curIndex.byteIndex = 0;
-                   curIndex.linePtr = linePtr;
-                   chunkPtr = NULL;
-                   goto connectNextLogicalLine;
-               }
-           }
-       }
-
-       chunkPtr = NULL;
-    }
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-    FinalizeBaseChunk(NULL);
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-    if (noCharsYet) {
-       dlPtr->spaceAbove = 0;
-       dlPtr->spaceBelow = 0;
-       dlPtr->length = 0;
-
-       /*
-        * We used to Tcl_Panic here, saying that LayoutDLine couldn't place
-        * any characters on a line, but I believe a more appropriate response
-        * is to return a DLine with zero height. With elided lines, tag
-        * transitions and asynchronous line height calculations, it is hard
-        * to avoid this situation ever arising with the current code design.
-        */
-
-       return dlPtr;
-    }
-    wholeLine = (segPtr == NULL);
-
-    /*
-     * We're at the end of the display line. Throw away everything after the
-     * most recent word break, if there is one; this may potentially require
-     * the last chunk to be layed out again.
-     */
-
-    if (breakChunkPtr == NULL) {
-       /*
-        * This code makes sure that we don't accidentally display chunks with
-        * no characters at the end of the line (such as the insertion
-        * cursor). These chunks belong on the next line. So, throw away
-        * everything after the last chunk that has characters in it.
-        */
-
-       breakChunkPtr = lastCharChunkPtr;
-       breakByteOffset = breakChunkPtr->numBytes;
-    }
-    if ((breakChunkPtr != NULL) && ((lastChunkPtr != breakChunkPtr)
-           || (breakByteOffset != lastChunkPtr->numBytes))) {
-       while (1) {
-           chunkPtr = breakChunkPtr->nextPtr;
-           if (chunkPtr == NULL) {
-               break;
-           }
-           FreeStyle(textPtr, chunkPtr->stylePtr);
-           breakChunkPtr->nextPtr = chunkPtr->nextPtr;
-           if (chunkPtr->undisplayProc != NULL) {
-               chunkPtr->undisplayProc(textPtr, chunkPtr);
-           }
-           ckfree(chunkPtr);
-       }
-       if (breakByteOffset != breakChunkPtr->numBytes) {
-           if (breakChunkPtr->undisplayProc != NULL) {
-               breakChunkPtr->undisplayProc(textPtr, breakChunkPtr);
-           }
-           segPtr = TkTextIndexToSeg(&breakIndex, &byteOffset);
-           segPtr->typePtr->layoutProc(textPtr, &breakIndex, segPtr,
-                   byteOffset, maxX, breakByteOffset, 0, wrapMode,
-                   breakChunkPtr);
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-           FinalizeBaseChunk(NULL);
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-       }
-       lastChunkPtr = breakChunkPtr;
-       wholeLine = 0;
-    }
-
-    /*
-     * Make tab adjustments for the last tab stop, if there is one.
-     */
-
-    if ((tabIndex >= 0) && (tabChunkPtr != NULL)) {
-       AdjustForTab(textPtr, tabArrayPtr, tabIndex, tabChunkPtr);
-    }
-
-    /*
-     * Make one more pass over the line to recompute various things like its
-     * height, length, and total number of bytes. Also modify the x-locations
-     * of chunks to reflect justification. If we're not wrapping, I'm not sure
-     * what is the best way to handle left and center justification: should
-     * the total length, for purposes of justification, be (a) the window
-     * width, (b) the length of the longest line in the window, or (c) the
-     * length of the longest line in the text? (c) isn't available, (b) seems
-     * weird, since it can change with vertical scrolling, so (a) is what is
-     * implemented below.
-     */
-
-    if (wrapMode == TEXT_WRAPMODE_NONE) {
-       maxX = textPtr->dInfoPtr->maxX - textPtr->dInfoPtr->x - rMargin;
-    }
-    dlPtr->length = lastChunkPtr->x + lastChunkPtr->width;
-    if (justify == TK_JUSTIFY_LEFT) {
-       jIndent = 0;
-    } else if (justify == TK_JUSTIFY_RIGHT) {
-       jIndent = maxX - dlPtr->length;
-    } else {
-       jIndent = (maxX - dlPtr->length)/2;
-    }
-    ascent = descent = 0;
-    for (chunkPtr = dlPtr->chunkPtr; chunkPtr != NULL;
-           chunkPtr = chunkPtr->nextPtr) {
-       chunkPtr->x += jIndent;
-       dlPtr->byteCount += chunkPtr->numBytes;
-       if (chunkPtr->minAscent > ascent) {
-           ascent = chunkPtr->minAscent;
-       }
-       if (chunkPtr->minDescent > descent) {
-           descent = chunkPtr->minDescent;
-       }
-       if (chunkPtr->minHeight > dlPtr->height) {
-           dlPtr->height = chunkPtr->minHeight;
-       }
-       sValuePtr = chunkPtr->stylePtr->sValuePtr;
-       if ((sValuePtr->borderWidth > 0)
-               && (sValuePtr->relief != TK_RELIEF_FLAT)) {
-           dlPtr->flags |= HAS_3D_BORDER;
-       }
-    }
-    if (dlPtr->height < (ascent + descent)) {
-       dlPtr->height = ascent + descent;
-       dlPtr->baseline = ascent;
-    } else {
-       dlPtr->baseline = ascent + (dlPtr->height - ascent - descent)/2;
-    }
-    sValuePtr = dlPtr->chunkPtr->stylePtr->sValuePtr;
-    if (dlPtr->index.byteIndex == 0) {
-       dlPtr->spaceAbove = sValuePtr->spacing1;
-    } else {
-       dlPtr->spaceAbove = sValuePtr->spacing2 - sValuePtr->spacing2/2;
-    }
-    if (wholeLine) {
-       dlPtr->spaceBelow = sValuePtr->spacing3;
-    } else {
-       dlPtr->spaceBelow = sValuePtr->spacing2/2;
-    }
-    dlPtr->height += dlPtr->spaceAbove + dlPtr->spaceBelow;
-    dlPtr->baseline += dlPtr->spaceAbove;
-
-    /*
-     * Recompute line length: may have changed because of justification.
-     */
-
-    dlPtr->length = lastChunkPtr->x + lastChunkPtr->width;
-
-    return dlPtr;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * UpdateDisplayInfo --
- *
- *     This function is invoked to recompute some or all of the DLine
- *     structures for a text widget. At the time it is called the DLine
- *     structures still left in the widget are guaranteed to be correct
- *     except that (a) the y-coordinates aren't necessarily correct, (b)
- *     there may be missing structures (the DLine structures get removed as
- *     soon as they are potentially out-of-date), and (c) DLine structures
- *     that don't start at the beginning of a line may be incorrect if
- *     previous information in the same line changed size in a way that moved
- *     a line boundary (DLines for any info that changed will have been
- *     deleted, but not DLines for unchanged info in the same text line).
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Upon return, the DLine information for textPtr correctly reflects the
- *     positions where characters will be displayed. However, this function
- *     doesn't actually bring the display up-to-date.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-UpdateDisplayInfo(
-    TkText *textPtr)           /* Text widget to update. */
-{
-    register TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    register DLine *dlPtr, *prevPtr;
-    TkTextIndex index;
-    TkTextLine *lastLinePtr;
-    int y, maxY, xPixelOffset, maxOffset, lineHeight;
-
-    if (!(dInfoPtr->flags & DINFO_OUT_OF_DATE)) {
-       return;
-    }
-    dInfoPtr->flags &= ~DINFO_OUT_OF_DATE;
-
-    /*
-     * Delete any DLines that are now above the top of the window.
-     */
-
-    index = textPtr->topIndex;
-    dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &index);
-    if ((dlPtr != NULL) && (dlPtr != dInfoPtr->dLinePtr)) {
-       FreeDLines(textPtr, dInfoPtr->dLinePtr, dlPtr, DLINE_UNLINK);
-    }
-    if (index.byteIndex == 0) {
-       lineHeight = 0;
-    } else {
-       lineHeight = -1;
-    }
-
-    /*
-     * Scan through the contents of the window from top to bottom, recomputing
-     * information for lines that are missing.
-     */
-
-    lastLinePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, textPtr,
-           TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr));
-    dlPtr = dInfoPtr->dLinePtr;
-    prevPtr = NULL;
-    y = dInfoPtr->y - dInfoPtr->newTopPixelOffset;
-    maxY = dInfoPtr->maxY;
-    while (1) {
-       register DLine *newPtr;
-
-       if (index.linePtr == lastLinePtr) {
-           break;
-       }
-
-       /*
-        * There are three possibilities right now:
-        * (a) the next DLine (dlPtr) corresponds exactly to the next
-        *     information we want to display: just use it as-is.
-        * (b) the next DLine corresponds to a different line, or to a segment
-        *     that will be coming later in the same line: leave this DLine
-        *     alone in the hopes that we'll be able to use it later, then
-        *     create a new DLine in front of it.
-        * (c) the next DLine corresponds to a segment in the line we want,
-        *     but it's a segment that has already been processed or will
-        *     never be processed. Delete the DLine and try again.
-        *
-        * One other twist on all this. It's possible for 3D borders to
-        * interact between lines (see DisplayLineBackground) so if a line is
-        * relayed out and has styles with 3D borders, its neighbors have to
-        * be redrawn if they have 3D borders too, since the interactions
-        * could have changed (the neighbors don't have to be relayed out,
-        * just redrawn).
-        */
-
-       if ((dlPtr == NULL) || (dlPtr->index.linePtr != index.linePtr)) {
-           /*
-            * Case (b) -- must make new DLine.
-            */
-
-       makeNewDLine:
-           if (tkTextDebug) {
-               char string[TK_POS_CHARS];
-
-               /*
-                * Debugging is enabled, so keep a log of all the lines that
-                * were re-layed out. The test suite uses this information.
-                */
-
-               TkTextPrintIndex(textPtr, &index, string);
-               LOG("tk_textRelayout", string);
-           }
-           newPtr = LayoutDLine(textPtr, &index);
-           if (prevPtr == NULL) {
-               dInfoPtr->dLinePtr = newPtr;
-           } else {
-               prevPtr->nextPtr = newPtr;
-               if (prevPtr->flags & HAS_3D_BORDER) {
-                   prevPtr->flags |= OLD_Y_INVALID;
-               }
-           }
-           newPtr->nextPtr = dlPtr;
-           dlPtr = newPtr;
-       } else {
-           /*
-            * DlPtr refers to the line we want. Next check the index within
-            * the line.
-            */
-
-           if (index.byteIndex == dlPtr->index.byteIndex) {
-               /*
-                * Case (a) - can use existing display line as-is.
-                */
-
-               if ((dlPtr->flags & HAS_3D_BORDER) && (prevPtr != NULL)
-                       && (prevPtr->flags & (NEW_LAYOUT))) {
-                   dlPtr->flags |= OLD_Y_INVALID;
-               }
-               goto lineOK;
-           }
-           if (index.byteIndex < dlPtr->index.byteIndex) {
-               goto makeNewDLine;
-           }
-
-           /*
-            * Case (c) - dlPtr is useless. Discard it and start again with
-            * the next display line.
-            */
-
-           newPtr = dlPtr->nextPtr;
-           FreeDLines(textPtr, dlPtr, newPtr, DLINE_FREE);
-           dlPtr = newPtr;
-           if (prevPtr != NULL) {
-               prevPtr->nextPtr = newPtr;
-           } else {
-               dInfoPtr->dLinePtr = newPtr;
-           }
-           continue;
-       }
-
-       /*
-        * Advance to the start of the next line.
-        */
-
-    lineOK:
-       dlPtr->y = y;
-       y += dlPtr->height;
-       if (lineHeight != -1) {
-           lineHeight += dlPtr->height;
-       }
-       TkTextIndexForwBytes(textPtr, &index, dlPtr->byteCount, &index);
-       prevPtr = dlPtr;
-       dlPtr = dlPtr->nextPtr;
-
-       /*
-        * If we switched text lines, delete any DLines left for the old text
-        * line.
-        */
-
-       if (index.linePtr != prevPtr->index.linePtr) {
-           register DLine *nextPtr;
-
-           nextPtr = dlPtr;
-           while ((nextPtr != NULL)
-                   && (nextPtr->index.linePtr == prevPtr->index.linePtr)) {
-               nextPtr = nextPtr->nextPtr;
-           }
-           if (nextPtr != dlPtr) {
-               FreeDLines(textPtr, dlPtr, nextPtr, DLINE_FREE);
-               prevPtr->nextPtr = nextPtr;
-               dlPtr = nextPtr;
-           }
-
-           if ((lineHeight != -1) && (TkBTreeLinePixelCount(textPtr,
-                   prevPtr->index.linePtr) != lineHeight)) {
-               /*
-                * The logical line height we just calculated is actually
-                * different to the currently cached height of the text line.
-                * That is fine (the text line heights are only calculated
-                * asynchronously), but we must update the cached height so
-                * that any counts made with DLine pointers are the same as
-                * counts made through the BTree. This helps to ensure that
-                * the scrollbar size corresponds accurately to that displayed
-                * contents, even as the window is re-sized.
-                */
-
-               TkBTreeAdjustPixelHeight(textPtr, prevPtr->index.linePtr,
-                       lineHeight, 0);
-
-               /*
-                * I believe we can be 100% sure that we started at the
-                * beginning of the logical line, so we can also adjust the
-                * 'pixelCalculationEpoch' to mark it as being up to date.
-                * There is a slight concern that we might not have got this
-                * right for the first line in the re-display.
-                */
-
-               TkBTreeLinePixelEpoch(textPtr, prevPtr->index.linePtr) =
-                       dInfoPtr->lineMetricUpdateEpoch;
-           }
-           lineHeight = 0;
-       }
-
-       /*
-        * It's important to have the following check here rather than in the
-        * while statement for the loop, so that there's always at least one
-        * DLine generated, regardless of how small the window is. This keeps
-        * a lot of other code from breaking.
-        */
-
-       if (y >= maxY) {
-           break;
-       }
-    }
-
-    /*
-     * Delete any DLine structures that don't fit on the screen.
-     */
-
-    FreeDLines(textPtr, dlPtr, NULL, DLINE_UNLINK);
-
-    /*
-     * If there is extra space at the bottom of the window (because we've hit
-     * the end of the text), then bring in more lines at the top of the
-     * window, if there are any, to fill in the view.
-     *
-     * Since the top line may only be partially visible, we try first to
-     * simply show more pixels from that line (newTopPixelOffset). If that
-     * isn't enough, we have to layout more lines.
-     */
-
-    if (y < maxY) {
-       /*
-        * This counts how many vertical pixels we have left to fill by
-        * pulling in more display pixels either from the first currently
-        * displayed, or the lines above it.
-        */
-
-       int spaceLeft = maxY - y;
-
-       if (spaceLeft <= dInfoPtr->newTopPixelOffset) {
-           /*
-            * We can fill up all the needed space just by showing more of the
-            * current top line.
-            */
-
-           dInfoPtr->newTopPixelOffset -= spaceLeft;
-           y += spaceLeft;
-           spaceLeft = 0;
-       } else {
-           int lineNum, bytesToCount;
-           DLine *lowestPtr;
-
-           /*
-            * Add in all of the current top line, which won't be enough to
-            * bring y up to maxY (if it was we would be in the 'if' block
-            * above).
-            */
-
-           y += dInfoPtr->newTopPixelOffset;
-           dInfoPtr->newTopPixelOffset = 0;
-
-           /*
-            * Layout an entire text line (potentially > 1 display line), then
-            * link in as many display lines as fit without moving the bottom
-            * line out of the window. Repeat this until all the extra space
-            * has been used up or we've reached the beginning of the text.
-            */
-
-           spaceLeft = maxY - y;
-           if (dInfoPtr->dLinePtr == NULL) {
-               /*
-                * No lines have been laid out. This must be an empty peer
-                * widget.
-                */
-
-                lineNum = TkBTreeNumLines(textPtr->sharedTextPtr->tree,
-                        textPtr) - 1;
-                bytesToCount = INT_MAX;
-           } else {
-               lineNum = TkBTreeLinesTo(textPtr,
-                       dInfoPtr->dLinePtr->index.linePtr);
-               bytesToCount = dInfoPtr->dLinePtr->index.byteIndex;
-               if (bytesToCount == 0) {
-                   bytesToCount = INT_MAX;
-                   lineNum--;
-               }
-           }
-           for ( ; (lineNum >= 0) && (spaceLeft > 0); lineNum--) {
-               int pixelHeight = 0;
-
-               index.linePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree,
-                       textPtr, lineNum);
-               index.byteIndex = 0;
-               lowestPtr = NULL;
-
-               do {
-                   dlPtr = LayoutDLine(textPtr, &index);
-                   pixelHeight += dlPtr->height;
-                   dlPtr->nextPtr = lowestPtr;
-                   lowestPtr = dlPtr;
-                   if (dlPtr->length == 0 && dlPtr->height == 0) {
-                       bytesToCount--;
-                       break;
-                   }   /* elide */
-                   TkTextIndexForwBytes(textPtr, &index, dlPtr->byteCount,
-                           &index);
-                   bytesToCount -= dlPtr->byteCount;
-               } while ((bytesToCount > 0)
-                       && (index.linePtr == lowestPtr->index.linePtr));
-
-               /*
-                * We may not have examined the entire line (depending on the
-                * value of 'bytesToCount', so we only want to set this if it
-                * is genuinely bigger).
-                */
-
-               if (pixelHeight > TkBTreeLinePixelCount(textPtr,
-                       lowestPtr->index.linePtr)) {
-                   TkBTreeAdjustPixelHeight(textPtr,
-                           lowestPtr->index.linePtr, pixelHeight, 0);
-                   if (index.linePtr != lowestPtr->index.linePtr) {
-                       /*
-                        * We examined the entire line, so can update the
-                        * epoch.
-                        */
-
-                       TkBTreeLinePixelEpoch(textPtr,
-                               lowestPtr->index.linePtr) =
-                               dInfoPtr->lineMetricUpdateEpoch;
-                   }
-               }
-
-               /*
-                * Scan through the display lines from the bottom one up to
-                * the top one.
-                */
-
-               while (lowestPtr != NULL) {
-                   dlPtr = lowestPtr;
-                   spaceLeft -= dlPtr->height;
-                   lowestPtr = dlPtr->nextPtr;
-                   dlPtr->nextPtr = dInfoPtr->dLinePtr;
-                   dInfoPtr->dLinePtr = dlPtr;
-                   if (tkTextDebug) {
-                       char string[TK_POS_CHARS];
-
-                       TkTextPrintIndex(textPtr, &dlPtr->index, string);
-                       LOG("tk_textRelayout", string);
-                   }
-                   if (spaceLeft <= 0) {
-                       break;
-                   }
-               }
-               FreeDLines(textPtr, lowestPtr, NULL, DLINE_FREE);
-               bytesToCount = INT_MAX;
-           }
-
-           /*
-            * We've either filled in the space we wanted to or we've run out
-            * of display lines at the top of the text. Note that we already
-            * set dInfoPtr->newTopPixelOffset to zero above.
-            */
-
-           if (spaceLeft < 0) {
-               /*
-                * We've laid out a few too many vertical pixels at or above
-                * the first line. Therefore we only want to show part of the
-                * first displayed line, so that the last displayed line just
-                * fits in the window.
-                */
-
-               dInfoPtr->newTopPixelOffset = -spaceLeft;
-               if (dInfoPtr->newTopPixelOffset>=dInfoPtr->dLinePtr->height) {
-                   /*
-                    * Somehow the entire first line we laid out is shorter
-                    * than the new offset. This should not occur and would
-                    * indicate a bad problem in the logic above.
-                    */
-
-                   Tcl_Panic("Error in pixel height consistency while filling in spacesLeft");
-               }
-           }
-       }
-
-       /*
-        * Now we're all done except that the y-coordinates in all the DLines
-        * are wrong and the top index for the text is wrong. Update them.
-        */
-
-       if (dInfoPtr->dLinePtr != NULL) {
-           textPtr->topIndex = dInfoPtr->dLinePtr->index;
-           y = dInfoPtr->y - dInfoPtr->newTopPixelOffset;
-           for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL;
-                   dlPtr = dlPtr->nextPtr) {
-               if (y > dInfoPtr->maxY) {
-                   Tcl_Panic("Added too many new lines in UpdateDisplayInfo");
-               }
-               dlPtr->y = y;
-               y += dlPtr->height;
-           }
-       }
-    }
-
-    /*
-     * If the old top or bottom line has scrolled elsewhere on the screen, we
-     * may not be able to re-use its old contents by copying bits (e.g., a
-     * beveled edge that was drawn when it was at the top or bottom won't be
-     * drawn when the line is in the middle and its neighbor has a matching
-     * background). Similarly, if the new top or bottom line came from
-     * somewhere else on the screen, we may not be able to copy the old bits.
-     */
-
-    dlPtr = dInfoPtr->dLinePtr;
-    if (dlPtr != NULL) {
-       if ((dlPtr->flags & HAS_3D_BORDER) && !(dlPtr->flags & TOP_LINE)) {
-           dlPtr->flags |= OLD_Y_INVALID;
-       }
-       while (1) {
-           if ((dlPtr->flags & TOP_LINE) && (dlPtr != dInfoPtr->dLinePtr)
-                   && (dlPtr->flags & HAS_3D_BORDER)) {
-               dlPtr->flags |= OLD_Y_INVALID;
-           }
-
-           /*
-            * If the old top-line was not completely showing (i.e. the
-            * pixelOffset is non-zero) and is no longer the top-line, then we
-            * must re-draw it.
-            */
-
-           if ((dlPtr->flags & TOP_LINE) &&
-                   dInfoPtr->topPixelOffset!=0 && dlPtr!=dInfoPtr->dLinePtr) {
-               dlPtr->flags |= OLD_Y_INVALID;
-           }
-           if ((dlPtr->flags & BOTTOM_LINE) && (dlPtr->nextPtr != NULL)
-                   && (dlPtr->flags & HAS_3D_BORDER)) {
-               dlPtr->flags |= OLD_Y_INVALID;
-           }
-           if (dlPtr->nextPtr == NULL) {
-               if ((dlPtr->flags & HAS_3D_BORDER)
-                       && !(dlPtr->flags & BOTTOM_LINE)) {
-                   dlPtr->flags |= OLD_Y_INVALID;
-               }
-               dlPtr->flags &= ~TOP_LINE;
-               dlPtr->flags |= BOTTOM_LINE;
-               break;
-           }
-           dlPtr->flags &= ~(TOP_LINE|BOTTOM_LINE);
-           dlPtr = dlPtr->nextPtr;
-       }
-       dInfoPtr->dLinePtr->flags |= TOP_LINE;
-       dInfoPtr->topPixelOffset = dInfoPtr->newTopPixelOffset;
-    }
-
-    /*
-     * Arrange for scrollbars to be updated.
-     */
-
-    textPtr->flags |= UPDATE_SCROLLBARS;
-
-    /*
-     * Deal with horizontal scrolling:
-     * 1. If there's empty space to the right of the longest line, shift the
-     *   screen to the right to fill in the empty space.
-     * 2. If the desired horizontal scroll position has changed, force a full
-     *   redisplay of all the lines in the widget.
-     * 3. If the wrap mode isn't "none" then re-scroll to the base position.
-     */
-
-    dInfoPtr->maxLength = 0;
-    for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL;
-           dlPtr = dlPtr->nextPtr) {
-       if (dlPtr->length > dInfoPtr->maxLength) {
-           dInfoPtr->maxLength = dlPtr->length;
-       }
-    }
-    maxOffset = dInfoPtr->maxLength - (dInfoPtr->maxX - dInfoPtr->x);
-
-    xPixelOffset = dInfoPtr->newXPixelOffset;
-    if (xPixelOffset > maxOffset) {
-       xPixelOffset = maxOffset;
-    }
-    if (xPixelOffset < 0) {
-       xPixelOffset = 0;
-    }
-
-    /*
-     * Here's a problem: see the tests textDisp-29.2.1-4
-     *
-     * If the widget is being created, but has not yet been configured it will
-     * have a maxY of 1 above, and we we won't have examined all the lines
-     * (just the first line, in fact), and so maxOffset will not be a true
-     * reflection of the widget's lines. Therefore we must not overwrite the
-     * original newXPixelOffset in this case.
-     */
-
-    if (!(((Tk_FakeWin *) (textPtr->tkwin))->flags & TK_NEED_CONFIG_NOTIFY)) {
-       dInfoPtr->newXPixelOffset = xPixelOffset;
-    }
-
-    if (xPixelOffset != dInfoPtr->curXPixelOffset) {
-       dInfoPtr->curXPixelOffset = xPixelOffset;
-       for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL;
-               dlPtr = dlPtr->nextPtr) {
-           dlPtr->flags |= OLD_Y_INVALID;
-       }
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * FreeDLines --
- *
- *     This function is called to free up all of the resources associated
- *     with one or more DLine structures.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Memory gets freed and various other resources are released.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-FreeDLines(
-    TkText *textPtr,           /* Information about overall text widget. */
-    register DLine *firstPtr,  /* Pointer to first DLine to free up. */
-    DLine *lastPtr,            /* Pointer to DLine just after last one to
-                                * free (NULL means everything starting with
-                                * firstPtr). */
-    int action)                        /* DLINE_UNLINK means DLines are currently
-                                * linked into the list rooted at
-                                * textPtr->dInfoPtr->dLinePtr and they have
-                                * to be unlinked. DLINE_FREE means just free
-                                * without unlinking. DLINE_FREE_TEMP means
-                                * the DLine given is just a temporary one and
-                                * we shouldn't invalidate anything for the
-                                * overall widget. */
-{
-    register TkTextDispChunk *chunkPtr, *nextChunkPtr;
-    register DLine *nextDLinePtr;
-
-    if (action == DLINE_FREE_TEMP) {
-       lineHeightsRecalculated++;
-       if (tkTextDebug) {
-           char string[TK_POS_CHARS];
-
-           /*
-            * Debugging is enabled, so keep a log of all the lines whose
-            * height was recalculated. The test suite uses this information.
-            */
-
-           TkTextPrintIndex(textPtr, &firstPtr->index, string);
-           LOG("tk_textHeightCalc", string);
-       }
-    } else if (action == DLINE_UNLINK) {
-       if (textPtr->dInfoPtr->dLinePtr == firstPtr) {
-           textPtr->dInfoPtr->dLinePtr = lastPtr;
-       } else {
-           register DLine *prevPtr;
-
-           for (prevPtr = textPtr->dInfoPtr->dLinePtr;
-                   prevPtr->nextPtr != firstPtr; prevPtr = prevPtr->nextPtr) {
-               /* Empty loop body. */
-           }
-           prevPtr->nextPtr = lastPtr;
-       }
-    }
-    while (firstPtr != lastPtr) {
-       nextDLinePtr = firstPtr->nextPtr;
-       for (chunkPtr = firstPtr->chunkPtr; chunkPtr != NULL;
-               chunkPtr = nextChunkPtr) {
-           if (chunkPtr->undisplayProc != NULL) {
-               chunkPtr->undisplayProc(textPtr, chunkPtr);
-           }
-           FreeStyle(textPtr, chunkPtr->stylePtr);
-           nextChunkPtr = chunkPtr->nextPtr;
-           ckfree(chunkPtr);
-       }
-       ckfree(firstPtr);
-       firstPtr = nextDLinePtr;
-    }
-    if (action != DLINE_FREE_TEMP) {
-       textPtr->dInfoPtr->dLinesInvalidated = 1;
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * DisplayDLine --
- *
- *     This function is invoked to draw a single line on the screen.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The line given by dlPtr is drawn at its correct position in textPtr's
- *     window. Note that this is one *display* line, not one *text* line.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-DisplayDLine(
-    TkText *textPtr,           /* Text widget in which to draw line. */
-    register DLine *dlPtr,     /* Information about line to draw. */
-    DLine *prevPtr,            /* Line just before one to draw, or NULL if
-                                * dlPtr is the top line. */
-    Pixmap pixmap)             /* Pixmap to use for double-buffering. Caller
-                                * must make sure it's large enough to hold
-                                * line. */
-{
-    register TkTextDispChunk *chunkPtr;
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    Display *display;
-    int height, y_off;
-#ifndef TK_NO_DOUBLE_BUFFERING
-    const int y = 0;
-#else
-    const int y = dlPtr->y;
-#endif /* TK_NO_DOUBLE_BUFFERING */
-
-    if (dlPtr->chunkPtr == NULL) return;
-
-    display = Tk_Display(textPtr->tkwin);
-
-    height = dlPtr->height;
-    if ((height + dlPtr->y) > dInfoPtr->maxY) {
-       height = dInfoPtr->maxY - dlPtr->y;
-    }
-    if (dlPtr->y < dInfoPtr->y) {
-       y_off = dInfoPtr->y - dlPtr->y;
-       height -= y_off;
-    } else {
-       y_off = 0;
-    }
-
-#ifdef TK_NO_DOUBLE_BUFFERING
-    TkpClipDrawableToRect(display, pixmap, dInfoPtr->x, y + y_off,
-           dInfoPtr->maxX - dInfoPtr->x, height);
-#endif /* TK_NO_DOUBLE_BUFFERING */
-
-    /*
-     * First, clear the area of the line to the background color for the text
-     * widget.
-     */
-
-    Tk_Fill3DRectangle(textPtr->tkwin, pixmap, textPtr->border, 0, y,
-           Tk_Width(textPtr->tkwin), dlPtr->height, 0, TK_RELIEF_FLAT);
-
-    /*
-     * Next, draw background information for the whole line.
-     */
-
-    DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap);
-
-    /*
-     * Make another pass through all of the chunks to redraw the insertion
-     * cursor, if it is visible on this line. Must do it here rather than in
-     * the foreground pass below because otherwise a wide insertion cursor
-     * will obscure the character to its left.
-     */
-
-    if (textPtr->state == TK_TEXT_STATE_NORMAL) {
-       for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL);
-               chunkPtr = chunkPtr->nextPtr) {
-           if (chunkPtr->displayProc == TkTextInsertDisplayProc) {
-               int x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curXPixelOffset;
-
-               chunkPtr->displayProc(textPtr, chunkPtr, x,
-                       y + dlPtr->spaceAbove,
-                       dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
-                       dlPtr->baseline - dlPtr->spaceAbove, display, pixmap,
-                       dlPtr->y + dlPtr->spaceAbove);
-           }
-       }
-    }
-
-    /*
-     * Make yet another pass through all of the chunks to redraw all of
-     * foreground information. Note: we have to call the displayProc even for
-     * chunks that are off-screen. This is needed, for example, so that
-     * embedded windows can be unmapped in this case.
-     */
-
-    for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL);
-           chunkPtr = chunkPtr->nextPtr) {
-       if (chunkPtr->displayProc == TkTextInsertDisplayProc) {
-           /*
-            * Already displayed the insertion cursor above. Don't do it again
-            * here.
-            */
-
-           continue;
-       }
-
-       /*
-        * Don't call if elide. This tax OK since not very many visible DLines
-        * in an area, but potentially many elide ones.
-        */
-
-       if (chunkPtr->displayProc != NULL) {
-           int x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curXPixelOffset;
-
-           if ((x + chunkPtr->width <= 0) || (x >= dInfoPtr->maxX)) {
-               /*
-                * Note: we have to call the displayProc even for chunks that
-                * are off-screen. This is needed, for example, so that
-                * embedded windows can be unmapped in this case. Display the
-                * chunk at a coordinate that can be clearly identified by the
-                * displayProc as being off-screen to the left (the
-                * displayProc may not be able to tell if something is off to
-                * the right).
-                */
-
-               x = -chunkPtr->width;
-           }
-           chunkPtr->displayProc(textPtr, chunkPtr, x,
-                   y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove -
-                   dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove,
-                   display, pixmap, dlPtr->y + dlPtr->spaceAbove);
-       }
-
-       if (dInfoPtr->dLinesInvalidated) {
-           return;
-       }
-    }
-
-#ifndef TK_NO_DOUBLE_BUFFERING
-    /*
-     * Copy the pixmap onto the screen. If this is the first or last line on
-     * the screen then copy a piece of the line, so that it doesn't overflow
-     * into the border area. Another special trick: copy the padding area to
-     * the left of the line; this is because the insertion cursor sometimes
-     * overflows onto that area and we want to get as much of the cursor as
-     * possible.
-     */
-
-    XCopyArea(display, pixmap, Tk_WindowId(textPtr->tkwin), dInfoPtr->copyGC,
-           dInfoPtr->x, y + y_off, (unsigned) (dInfoPtr->maxX - dInfoPtr->x),
-           (unsigned) height, dInfoPtr->x, dlPtr->y + y_off);
-#else
-    TkpClipDrawableToRect(display, pixmap, 0, 0, -1, -1);
-#endif /* TK_NO_DOUBLE_BUFFERING */
-    linesRedrawn++;
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * DisplayLineBackground --
- *
- *     This function is called to fill in the background for a display line.
- *     It draws 3D borders cleverly so that adjacent chunks with the same
- *     style (whether on the same line or different lines) have a single 3D
- *     border around the whole region.
- *
- * Results:
- *     There is no return value. Pixmap is filled in with background
- *     information for dlPtr.
- *
- * Side effects:
- *     None.
- *
- *--------------------------------------------------------------
- */
-
-static void
-DisplayLineBackground(
-    TkText *textPtr,           /* Text widget containing line. */
-    register DLine *dlPtr,     /* Information about line to draw. */
-    DLine *prevPtr,            /* Line just above dlPtr, or NULL if dlPtr is
-                                * the top-most line in the window. */
-    Pixmap pixmap)             /* Pixmap to use for double-buffering. Caller
-                                * must make sure it's large enough to hold
-                                * line. Caller must also have filled it with
-                                * the background color for the widget. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    TkTextDispChunk *chunkPtr; /* Pointer to chunk in the current line. */
-    TkTextDispChunk *chunkPtr2;        /* Pointer to chunk in the line above or below
-                                * the current one. NULL if we're to the left
-                                * of or to the right of the chunks in the
-                                * line. */
-    TkTextDispChunk *nextPtr2; /* Next chunk after chunkPtr2 (it's not the
-                                * same as chunkPtr2->nextPtr in the case
-                                * where chunkPtr2 is NULL because the line is
-                                * indented). */
-    int leftX;                 /* The left edge of the region we're currently
-                                * working on. */
-    int leftXIn;               /* 1 means beveled edge at leftX slopes right
-                                * as it goes down, 0 means it slopes left as
-                                * it goes down. */
-    int rightX;                        /* Right edge of chunkPtr. */
-    int rightX2;               /* Right edge of chunkPtr2. */
-    int matchLeft;             /* Does the style of this line match that of
-                                * its neighbor just to the left of the
-                                * current x coordinate? */
-    int matchRight;            /* Does line's style match its neighbor just
-                                * to the right of the current x-coord? */
-    int minX, maxX, xOffset;
-    StyleValues *sValuePtr;
-    Display *display;
-#ifndef TK_NO_DOUBLE_BUFFERING
-    const int y = 0;
-#else
-    const int y = dlPtr->y;
-#endif /* TK_NO_DOUBLE_BUFFERING */
-
-    /*
-     * Pass 1: scan through dlPtr from left to right. For each range of chunks
-     * with the same style, draw the main background for the style plus the
-     * vertical parts of the 3D borders (the left and right edges).
-     */
-
-    display = Tk_Display(textPtr->tkwin);
-    minX = dInfoPtr->curXPixelOffset;
-    xOffset = dInfoPtr->x - minX;
-    maxX = minX + dInfoPtr->maxX - dInfoPtr->x;
-    chunkPtr = dlPtr->chunkPtr;
-
-    /*
-     * Note A: in the following statement, and a few others later in this file
-     * marked with "See Note A above", the right side of the assignment was
-     * replaced with 0 on 6/18/97. This has the effect of highlighting the
-     * empty space to the left of a line whenever the leftmost character of
-     * the line is highlighted. This way, multi-line highlights always line up
-     * along their left edges. However, this may look funny in the case where
-     * a single word is highlighted. To undo the change, replace "leftX = 0"
-     * with "leftX = chunkPtr->x" and "rightX2 = 0" with "rightX2 =
-     * nextPtr2->x" here and at all the marked points below. This restores the
-     * old behavior where empty space to the left of a line is not
-     * highlighted, leaving a ragged left edge for multi-line highlights.
-     */
-
-    leftX = 0;
-    for (; leftX < maxX; chunkPtr = chunkPtr->nextPtr) {
-       if ((chunkPtr->nextPtr != NULL)
-               && SAME_BACKGROUND(chunkPtr->nextPtr->stylePtr,
-               chunkPtr->stylePtr)) {
-           continue;
-       }
-       sValuePtr = chunkPtr->stylePtr->sValuePtr;
-       rightX = chunkPtr->x + chunkPtr->width;
-       if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) {
-           rightX = maxX;
-       }
-       if (chunkPtr->stylePtr->bgGC != None) {
-           /*
-            * Not visible - bail out now.
-            */
-
-           if (rightX + xOffset <= 0) {
-               leftX = rightX;
-               continue;
-           }
-
-           /*
-            * Trim the start position for drawing to be no further away than
-            * -borderWidth. The reason is that on many X servers drawing from
-            * -32768 (or less) to +something simply does not display
-            * correctly. [Patch #541999]
-            */
-
-           if ((leftX + xOffset) < -(sValuePtr->borderWidth)) {
-               leftX = -sValuePtr->borderWidth - xOffset;
-           }
-           if ((rightX - leftX) > 32767) {
-               rightX = leftX + 32767;
-           }
-
-           XFillRectangle(display, pixmap, chunkPtr->stylePtr->bgGC,
-                   leftX + xOffset, y, (unsigned int) (rightX - leftX),
-                   (unsigned int) dlPtr->height);
-           if (sValuePtr->relief != TK_RELIEF_FLAT) {
-               Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
-                       leftX + xOffset, y, sValuePtr->borderWidth,
-                       dlPtr->height, 1, sValuePtr->relief);
-               Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
-                       rightX - sValuePtr->borderWidth + xOffset,
-                       y, sValuePtr->borderWidth, dlPtr->height, 0,
-                       sValuePtr->relief);
-           }
-       }
-       leftX = rightX;
-    }
-
-    /*
-     * Pass 2: draw the horizontal bevels along the top of the line. To do
-     * this, scan through dlPtr from left to right while simultaneously
-     * scanning through the line just above dlPtr. ChunkPtr2 and nextPtr2
-     * refer to two adjacent chunks in the line above.
-     */
-
-    chunkPtr = dlPtr->chunkPtr;
-    leftX = 0;                         /* See Note A above. */
-    leftXIn = 1;
-    rightX = chunkPtr->x + chunkPtr->width;
-    if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) {
-       rightX = maxX;
-    }
-    chunkPtr2 = NULL;
-    if (prevPtr != NULL && prevPtr->chunkPtr != NULL) {
-       /*
-        * Find the chunk in the previous line that covers leftX.
-        */
-
-       nextPtr2 = prevPtr->chunkPtr;
-       rightX2 = 0;                    /* See Note A above. */
-       while (rightX2 <= leftX) {
-           chunkPtr2 = nextPtr2;
-           if (chunkPtr2 == NULL) {
-               break;
-           }
-           nextPtr2 = chunkPtr2->nextPtr;
-           rightX2 = chunkPtr2->x + chunkPtr2->width;
-           if (nextPtr2 == NULL) {
-               rightX2 = INT_MAX;
-           }
-       }
-    } else {
-       nextPtr2 = NULL;
-       rightX2 = INT_MAX;
-    }
-
-    while (leftX < maxX) {
-       matchLeft = (chunkPtr2 != NULL)
-               && SAME_BACKGROUND(chunkPtr2->stylePtr, chunkPtr->stylePtr);
-       sValuePtr = chunkPtr->stylePtr->sValuePtr;
-       if (rightX <= rightX2) {
-           /*
-            * The chunk in our line is about to end. If its style changes
-            * then draw the bevel for the current style.
-            */
-
-           if ((chunkPtr->nextPtr == NULL)
-                   || !SAME_BACKGROUND(chunkPtr->stylePtr,
-                   chunkPtr->nextPtr->stylePtr)) {
-               if (!matchLeft && (sValuePtr->relief != TK_RELIEF_FLAT)) {
-                   Tk_3DHorizontalBevel(textPtr->tkwin, pixmap,
-                           sValuePtr->border, leftX + xOffset, y,
-                           rightX - leftX, sValuePtr->borderWidth, leftXIn,
-                           1, 1, sValuePtr->relief);
-               }
-               leftX = rightX;
-               leftXIn = 1;
-
-               /*
-                * If the chunk in the line above is also ending at the same
-                * point then advance to the next chunk in that line.
-                */
-
-               if ((rightX == rightX2) && (chunkPtr2 != NULL)) {
-                   goto nextChunk2;
-               }
-           }
-           chunkPtr = chunkPtr->nextPtr;
-           if (chunkPtr == NULL) {
-               break;
-           }
-           rightX = chunkPtr->x + chunkPtr->width;
-           if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) {
-               rightX = maxX;
-           }
-           continue;
-       }
-
-       /*
-        * The chunk in the line above is ending at an x-position where there
-        * is no change in the style of the current line. If the style above
-        * matches the current line on one side of the change but not on the
-        * other, we have to draw an L-shaped piece of bevel.
-        */
-
-       matchRight = (nextPtr2 != NULL)
-               && SAME_BACKGROUND(nextPtr2->stylePtr, chunkPtr->stylePtr);
-       if (matchLeft && !matchRight) {
-           if (sValuePtr->relief != TK_RELIEF_FLAT) {
-               Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
-                       rightX2 - sValuePtr->borderWidth + xOffset, y,
-                       sValuePtr->borderWidth, sValuePtr->borderWidth, 0,
-                       sValuePtr->relief);
-           }
-           leftX = rightX2 - sValuePtr->borderWidth;
-           leftXIn = 0;
-       } else if (!matchLeft && matchRight
-               && (sValuePtr->relief != TK_RELIEF_FLAT)) {
-           Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
-                   rightX2 + xOffset, y, sValuePtr->borderWidth,
-                   sValuePtr->borderWidth, 1, sValuePtr->relief);
-           Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
-                   leftX + xOffset, y, rightX2 + sValuePtr->borderWidth -
-                   leftX, sValuePtr->borderWidth, leftXIn, 0, 1,
-                   sValuePtr->relief);
-       }
-
-    nextChunk2:
-       chunkPtr2 = nextPtr2;
-       if (chunkPtr2 == NULL) {
-           rightX2 = INT_MAX;
-       } else {
-           nextPtr2 = chunkPtr2->nextPtr;
-           rightX2 = chunkPtr2->x + chunkPtr2->width;
-           if (nextPtr2 == NULL) {
-               rightX2 = INT_MAX;
-           }
-       }
-    }
-
-    /*
-     * Pass 3: draw the horizontal bevels along the bottom of the line. This
-     * uses the same approach as pass 2.
-     */
-
-    chunkPtr = dlPtr->chunkPtr;
-    leftX = 0;                         /* See Note A above. */
-    leftXIn = 0;
-    rightX = chunkPtr->x + chunkPtr->width;
-    if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) {
-       rightX = maxX;
-    }
-    chunkPtr2 = NULL;
-    if (dlPtr->nextPtr != NULL && dlPtr->nextPtr->chunkPtr != NULL) {
-       /*
-        * Find the chunk in the previous line that covers leftX.
-        */
-
-       nextPtr2 = dlPtr->nextPtr->chunkPtr;
-       rightX2 = 0;                    /* See Note A above. */
-       while (rightX2 <= leftX) {
-           chunkPtr2 = nextPtr2;
-           if (chunkPtr2 == NULL) {
-               break;
-           }
-           nextPtr2 = chunkPtr2->nextPtr;
-           rightX2 = chunkPtr2->x + chunkPtr2->width;
-           if (nextPtr2 == NULL) {
-               rightX2 = INT_MAX;
-           }
-       }
-    } else {
-       nextPtr2 = NULL;
-       rightX2 = INT_MAX;
-    }
-
-    while (leftX < maxX) {
-       matchLeft = (chunkPtr2 != NULL)
-               && SAME_BACKGROUND(chunkPtr2->stylePtr, chunkPtr->stylePtr);
-       sValuePtr = chunkPtr->stylePtr->sValuePtr;
-       if (rightX <= rightX2) {
-           if ((chunkPtr->nextPtr == NULL)
-                   || !SAME_BACKGROUND(chunkPtr->stylePtr,
-                   chunkPtr->nextPtr->stylePtr)) {
-               if (!matchLeft && (sValuePtr->relief != TK_RELIEF_FLAT)) {
-                   Tk_3DHorizontalBevel(textPtr->tkwin, pixmap,
-                           sValuePtr->border, leftX + xOffset,
-                           y + dlPtr->height - sValuePtr->borderWidth,
-                           rightX - leftX, sValuePtr->borderWidth, leftXIn,
-                           0, 0, sValuePtr->relief);
-               }
-               leftX = rightX;
-               leftXIn = 0;
-               if ((rightX == rightX2) && (chunkPtr2 != NULL)) {
-                   goto nextChunk2b;
-               }
-           }
-           chunkPtr = chunkPtr->nextPtr;
-           if (chunkPtr == NULL) {
-               break;
-           }
-           rightX = chunkPtr->x + chunkPtr->width;
-           if ((chunkPtr->nextPtr == NULL) && (rightX < maxX)) {
-               rightX = maxX;
-           }
-           continue;
-       }
-
-       matchRight = (nextPtr2 != NULL)
-               && SAME_BACKGROUND(nextPtr2->stylePtr, chunkPtr->stylePtr);
-       if (matchLeft && !matchRight) {
-           if (sValuePtr->relief != TK_RELIEF_FLAT) {
-               Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
-                       rightX2 - sValuePtr->borderWidth + xOffset,
-                       y + dlPtr->height - sValuePtr->borderWidth,
-                       sValuePtr->borderWidth, sValuePtr->borderWidth, 0,
-                       sValuePtr->relief);
-           }
-           leftX = rightX2 - sValuePtr->borderWidth;
-           leftXIn = 1;
-       } else if (!matchLeft && matchRight
-               && (sValuePtr->relief != TK_RELIEF_FLAT)) {
-           Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
-                   rightX2 + xOffset, y + dlPtr->height -
-                   sValuePtr->borderWidth, sValuePtr->borderWidth,
-                   sValuePtr->borderWidth, 1, sValuePtr->relief);
-           Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
-                   leftX + xOffset, y + dlPtr->height -
-                   sValuePtr->borderWidth, rightX2 + sValuePtr->borderWidth -
-                   leftX, sValuePtr->borderWidth, leftXIn, 1, 0,
-                   sValuePtr->relief);
-       }
-
-    nextChunk2b:
-       chunkPtr2 = nextPtr2;
-       if (chunkPtr2 == NULL) {
-           rightX2 = INT_MAX;
-       } else {
-           nextPtr2 = chunkPtr2->nextPtr;
-           rightX2 = chunkPtr2->x + chunkPtr2->width;
-           if (nextPtr2 == NULL) {
-               rightX2 = INT_MAX;
-           }
-       }
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * AsyncUpdateLineMetrics --
- *
- *     This function is invoked as a background handler to update the pixel-
- *     height calculations of individual lines in an asychronous manner.
- *
- *     Currently a timer-handler is used for this purpose, which continuously
- *     reschedules itself. It may well be better to use some other approach
- *     (e.g., a background thread). We can't use an idle-callback because of
- *     a known bug in Tcl/Tk in which idle callbacks are not allowed to
- *     re-schedule themselves. This just causes an effective infinite loop.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Line heights may be recalculated.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-AsyncUpdateLineMetrics(
-    ClientData clientData)     /* Information about widget. */
-{
-    register TkText *textPtr = clientData;
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    int lineNum;
-
-    dInfoPtr->lineUpdateTimer = NULL;
-
-    if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
-       /*
-        * The widget has been deleted. Don't do anything.
-        */
-
-       if (--textPtr->refCount == 0) {
-           ckfree(textPtr);
-       }
-       return;
-    }
-
-    if (dInfoPtr->flags & REDRAW_PENDING) {
-       dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1,
-               AsyncUpdateLineMetrics, clientData);
-       return;
-    }
-
-    /*
-     * Reify where we end or all hell breaks loose with the calculations when
-     * we try to update. [Bug 2677890]
-     */
-
-    lineNum = dInfoPtr->currentMetricUpdateLine;
-    if (dInfoPtr->lastMetricUpdateLine == -1) {
-       dInfoPtr->lastMetricUpdateLine =
-               TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr);
-    }
-
-    /*
-     * Update the lines in blocks of about 24 recalculations, or 250+ lines
-     * examined, so we pass in 256 for 'doThisMuch'.
-     */
-
-    lineNum = TkTextUpdateLineMetrics(textPtr, lineNum,
-           dInfoPtr->lastMetricUpdateLine, 256);
-
-    if (tkTextDebug) {
-       char buffer[2 * TCL_INTEGER_SPACE + 1];
-
-       sprintf(buffer, "%d %d", lineNum, dInfoPtr->lastMetricUpdateLine);
-       LOG("tk_textInvalidateLine", buffer);
-    }
-
-    /*
-     * If we're not in the middle of a long-line calculation (metricEpoch==-1)
-     * and we've reached the last line, then we're done.
-     */
-
-    if (dInfoPtr->metricEpoch == -1
-           && lineNum == dInfoPtr->lastMetricUpdateLine) {
-       /*
-        * We have looped over all lines, so we're done. We must release our
-        * refCount on the widget (the timer token was already set to NULL
-        * above).
-        */
-
-       textPtr->refCount--;
-       if (textPtr->refCount == 0) {
-           ckfree(textPtr);
-       }
-       return;
-    }
-    dInfoPtr->currentMetricUpdateLine = lineNum;
-
-    /*
-     * Re-arm the timer. We already have a refCount on the text widget so no
-     * need to adjust that.
-     */
-
-    dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1,
-           AsyncUpdateLineMetrics, textPtr);
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextUpdateLineMetrics --
- *
- *     This function updates the pixel height calculations of a range of
- *     lines in the widget. The range is from lineNum to endLine, but, if
- *     doThisMuch is positive, then the function may return earlier, once a
- *     certain number of lines has been examined. The line counts are from 0.
- *
- *     If doThisMuch is -1, then all lines in the range will be updated. This
- *     will potentially take quite some time for a large text widget.
- *
- *     Note: with bad input for lineNum and endLine, this function can loop
- *     indefinitely.
- *
- * Results:
- *     The index of the last line examined (or -1 if we are about to wrap
- *     around from end to beginning of the widget, and the next line will be
- *     the first line).
- *
- * Side effects:
- *     Line heights may be recalculated.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkTextUpdateLineMetrics(
-    TkText *textPtr,           /* Information about widget. */
-    int lineNum,               /* Start at this line. */
-    int endLine,               /* Go no further than this line. */
-    int doThisMuch)            /* How many lines to check, or how many 10s of
-                                * lines to recalculate. If '-1' then do
-                                * everything in the range (which may take a
-                                * while). */
-{
-    TkTextLine *linePtr = NULL;
-    int count = 0;
-    int totalLines = TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr);
-
-    if (totalLines == 0) {
-       /*
-        * Empty peer widget.
-        */
-
-       return endLine;
-    }
-
-    while (1) {
-       /*
-        * Get a suitable line.
-        */
-
-       if (lineNum == -1 && linePtr == NULL) {
-           lineNum = 0;
-           linePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, textPtr,
-                   lineNum);
-       } else {
-           if (lineNum == -1 || linePtr == NULL) {
-               if (lineNum == -1) {
-                   lineNum = 0;
-               }
-               linePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree,
-                       textPtr, lineNum);
-           } else {
-               lineNum++;
-               linePtr = TkBTreeNextLine(textPtr, linePtr);
-           }
-
-           /*
-            * If we're in the middle of a partial-line height calculation,
-            * then we can't be done.
-            */
-
-           if (textPtr->dInfoPtr->metricEpoch == -1 && lineNum == endLine) {
-               /*
-                * We have looped over all lines, so we're done.
-                */
-
-               break;
-           }
-       }
-
-       if (lineNum < totalLines) {
-           if (tkTextDebug) {
-               char buffer[4 * TCL_INTEGER_SPACE + 3];
-
-               sprintf(buffer, "%d %d %d %d",
-                       lineNum, endLine, totalLines, count);
-               LOG("tk_textInvalidateLine", buffer);
-           }
-
-           /*
-            * Now update the line's metrics if necessary.
-            */
-
-           if (TkBTreeLinePixelEpoch(textPtr, linePtr)
-                   == textPtr->dInfoPtr->lineMetricUpdateEpoch) {
-               /*
-                * This line is already up to date. That means there's nothing
-                * to do here.
-                */
-           } else if (doThisMuch == -1) {
-               count += 8 * TkTextUpdateOneLine(textPtr, linePtr, 0,NULL,0);
-           } 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->sharedTextPtr->stateEpoch &&
-                       textPtr->dInfoPtr->metricIndex.linePtr==linePtr) {
-                   indexPtr = &textPtr->dInfoPtr->metricIndex;
-                   pixelHeight = textPtr->dInfoPtr->metricPixelHeight;
-               } else {
-                   /*
-                    * We must reset the partial line height calculation data
-                    * here, so we don't use it when it is out of date.
-                    */
-
-                   textPtr->dInfoPtr->metricEpoch = -1;
-                   index.tree = textPtr->sharedTextPtr->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, 1);
-
-               if (indexPtr->linePtr == linePtr) {
-                   /*
-                    * We didn't complete the logical line, because it
-                    * produced very many display lines, which must be because
-                    * 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) {
-                       /*
-                        * These have already been stored, unless we just
-                        * started the new line.
-                        */
-
-                       textPtr->dInfoPtr->metricIndex = index;
-                       textPtr->dInfoPtr->metricEpoch =
-                               textPtr->sharedTextPtr->stateEpoch;
-                   }
-                   textPtr->dInfoPtr->metricPixelHeight =
-                           TkBTreeLinePixelCount(textPtr, linePtr);
-                   break;
-               }
-
-               /*
-                * We're done with this long line.
-                */
-
-               textPtr->dInfoPtr->metricEpoch = -1;
-           }
-       } else {
-           /*
-            * We must never recalculate the height of the last artificial
-            * line. It must stay at zero, and if we recalculate it, it will
-            * change.
-            */
-
-           if (endLine >= totalLines) {
-               lineNum = endLine;
-               break;
-           }
-
-           /*
-            * Set things up for the next loop through.
-            */
-
-           lineNum = -1;
-       }
-       count++;
-
-       if (doThisMuch != -1 && count >= doThisMuch) {
-           break;
-       }
-    }
-    if (doThisMuch == -1) {
-       /*
-        * If we were requested to provide a full update, then also update the
-        * scrollbar.
-        */
-
-       GetYView(textPtr->interp, textPtr, 1);
-    }
-    return lineNum;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextInvalidateLineMetrics, TextInvalidateLineMetrics --
- *
- *     Mark a number of text lines as having invalid line metric
- *     calculations. Never call this with linePtr as the last (artificial)
- *     line in the text. Depending on 'action' which indicates whether the
- *     given lines are simply invalid or have been inserted or deleted, the
- *     pre-existing asynchronous line update range may need to be adjusted.
- *
- *     If linePtr is NULL then 'lineCount' and 'action' are ignored and all
- *     lines are invalidated.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     May schedule an asychronous callback.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextInvalidateLineMetrics(
-    TkSharedText *sharedTextPtr,/* Shared widget section for all peers, or
-                                * NULL. */
-    TkText *textPtr,           /* Widget record for text widget. */
-    TkTextLine *linePtr,       /* Invalidation starts from this line. */
-    int lineCount,             /* And includes this many following lines. */
-    int action)                        /* Indicates what type of invalidation
-                                * occurred (insert, delete, or simple). */
-{
-    if (sharedTextPtr == NULL) {
-       TextInvalidateLineMetrics(textPtr, linePtr, lineCount, action);
-    } else {
-       textPtr = sharedTextPtr->peers;
-       while (textPtr != NULL) {
-           TextInvalidateLineMetrics(textPtr, linePtr, lineCount, action);
-           textPtr = textPtr->next;
-       }
-    }
-}
-\f
-static void
-TextInvalidateLineMetrics(
-    TkText *textPtr,           /* Widget record for text widget. */
-    TkTextLine *linePtr,       /* Invalidation starts from this line. */
-    int lineCount,             /* And includes this many following lines. */
-    int action)                        /* Indicates what type of invalidation
-                                * occurred (insert, delete, or simple). */
-{
-    int fromLine;
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-
-    if (linePtr != NULL) {
-       int counter = lineCount;
-
-       fromLine = TkBTreeLinesTo(textPtr, linePtr);
-
-       /*
-        * Invalidate the height calculations of each line in the given range.
-        */
-
-       TkBTreeLinePixelEpoch(textPtr, linePtr) = 0;
-       while (counter > 0 && linePtr != NULL) {
-           linePtr = TkBTreeNextLine(textPtr, linePtr);
-           if (linePtr != NULL) {
-               TkBTreeLinePixelEpoch(textPtr, linePtr) = 0;
-           }
-           counter--;
-       }
-
-       /*
-        * Now schedule an examination of each line in the union of the old
-        * and new update ranges, including the (possibly empty) range in
-        * between. If that between range is not-empty, then we are examining
-        * more lines than is strictly necessary (but the examination of the
-        * extra lines should be quick, since their pixelCalculationEpoch will
-        * be up to date). However, to keep track of that would require more
-        * complex record-keeping than what we have.
-        */
-
-       if (dInfoPtr->lineUpdateTimer == NULL) {
-           dInfoPtr->currentMetricUpdateLine = fromLine;
-           if (action == TK_TEXT_INVALIDATE_DELETE) {
-               lineCount = 0;
-           }
-           dInfoPtr->lastMetricUpdateLine = fromLine + lineCount + 1;
-       } else {
-           int toLine = fromLine + lineCount + 1;
-
-           if (action == TK_TEXT_INVALIDATE_DELETE) {
-               if (toLine <= dInfoPtr->currentMetricUpdateLine) {
-                   dInfoPtr->currentMetricUpdateLine = fromLine;
-                   if (dInfoPtr->lastMetricUpdateLine != -1) {
-                       dInfoPtr->lastMetricUpdateLine -= lineCount;
-                   }
-               } else if (fromLine <= dInfoPtr->currentMetricUpdateLine) {
-                   dInfoPtr->currentMetricUpdateLine = fromLine;
-                   if (toLine <= dInfoPtr->lastMetricUpdateLine) {
-                       dInfoPtr->lastMetricUpdateLine -= lineCount;
-                   }
-               } else {
-                   if (dInfoPtr->lastMetricUpdateLine != -1) {
-                       dInfoPtr->lastMetricUpdateLine = toLine;
-                   }
-               }
-           } else if (action == TK_TEXT_INVALIDATE_INSERT) {
-               if (toLine <= dInfoPtr->currentMetricUpdateLine) {
-                   dInfoPtr->currentMetricUpdateLine = fromLine;
-                   if (dInfoPtr->lastMetricUpdateLine != -1) {
-                       dInfoPtr->lastMetricUpdateLine += lineCount;
-                   }
-               } else if (fromLine <= dInfoPtr->currentMetricUpdateLine) {
-                   dInfoPtr->currentMetricUpdateLine = fromLine;
-                   if (toLine <= dInfoPtr->lastMetricUpdateLine) {
-                       dInfoPtr->lastMetricUpdateLine += lineCount;
-                   }
-                   if (toLine > dInfoPtr->lastMetricUpdateLine) {
-                       dInfoPtr->lastMetricUpdateLine = toLine;
-                   }
-               } else {
-                   if (dInfoPtr->lastMetricUpdateLine != -1) {
-                       dInfoPtr->lastMetricUpdateLine = toLine;
-                   }
-               }
-           } else {
-               if (fromLine < dInfoPtr->currentMetricUpdateLine) {
-                   dInfoPtr->currentMetricUpdateLine = fromLine;
-               }
-               if (dInfoPtr->lastMetricUpdateLine != -1
-                       && toLine > dInfoPtr->lastMetricUpdateLine) {
-                   dInfoPtr->lastMetricUpdateLine = toLine;
-               }
-           }
-       }
-    } else {
-       /*
-        * This invalidates the height of all lines in the widget.
-        */
-
-       if ((++dInfoPtr->lineMetricUpdateEpoch) == 0) {
-           dInfoPtr->lineMetricUpdateEpoch++;
-       }
-
-       /*
-        * This has the effect of forcing an entire new loop of update checks
-        * on all lines in the widget.
-        */
-
-       if (dInfoPtr->lineUpdateTimer == NULL) {
-           dInfoPtr->currentMetricUpdateLine = -1;
-       }
-       dInfoPtr->lastMetricUpdateLine = dInfoPtr->currentMetricUpdateLine;
-    }
-
-    /*
-     * Now re-set the current update calculations.
-     */
-
-    if (dInfoPtr->lineUpdateTimer == NULL) {
-       textPtr->refCount++;
-       dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1,
-               AsyncUpdateLineMetrics, textPtr);
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextFindDisplayLineEnd --
- *
- *     This function is invoked to find the index of the beginning or end of
- *     the particular display line on which the given index sits, whether
- *     that line is displayed or not.
- *
- *     If 'end' is zero, we look for the start, and if 'end' is one we look
- *     for the end.
- *
- *     If the beginning of the current display line is elided, and we are
- *     looking for the start of the line, then the returned index will be the
- *     first elided index on the display line.
- *
- *     Similarly if the end of the current display line is elided and we are
- *     looking for the end, then the returned index will be the last elided
- *     index on the display line.
- *
- * Results:
- *     Modifies indexPtr to point to the given end.
- *
- *     If xOffset is non-NULL, it is set to the x-pixel offset of the given
- *     original index within the given display line.
- *
- * Side effects:
- *     The combination of 'LayoutDLine' and 'FreeDLines' seems like a rather
- *     time-consuming way of gathering the information we need, so this would
- *     be a good place to look to speed up the calculations. In particular
- *     these calls will map and unmap embedded windows respectively, which I
- *     would hope isn't exactly necessary!
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextFindDisplayLineEnd(
-    TkText *textPtr,           /* Widget record for text widget. */
-    TkTextIndex *indexPtr,     /* Index we will adjust to the display line
-                                * start or end. */
-    int end,                   /* 0 = start, 1 = end. */
-    int *xOffset)              /* NULL, or used to store the x-pixel offset
-                                * of the original index within its display
-                                * line. */
-{
-    TkTextIndex index;
-
-    if (!end && IsStartOfNotMergedLine(textPtr, indexPtr)) {
-       /*
-        * Nothing to do.
-        */
-
-       if (xOffset != NULL) {
-           *xOffset = 0;
-       }
-       return;
-    }
-
-    index = *indexPtr;
-    index.byteIndex = 0;
-    index.textPtr = NULL;
-
-    while (1) {
-       TkTextIndex endOfLastLine;
-
-       if (TkTextIndexBackBytes(textPtr, &index, 1, &endOfLastLine)) {
-           /*
-            * Reached beginning of text.
-            */
-
-           break;
-       }
-
-       if (!TkTextIsElided(textPtr, &endOfLastLine, NULL)) {
-           /*
-            * The eol is not elided, so 'index' points to the start of a
-            * display line (as well as logical line).
-            */
-
-           break;
-       }
-
-       /*
-        * indexPtr's logical line is actually merged with the previous
-        * logical line whose eol is elided. Continue searching back to get a
-        * real line start.
-        */
-
-       index = endOfLastLine;
-       index.byteIndex = 0;
-    }
-
-    while (1) {
-       DLine *dlPtr;
-       int byteCount;
-       TkTextIndex nextLineStart;
-
-       dlPtr = LayoutDLine(textPtr, &index);
-       byteCount = dlPtr->byteCount;
-
-       TkTextIndexForwBytes(textPtr, &index, byteCount, &nextLineStart);
-
-       /*
-        * 'byteCount' goes up to the beginning of the next display line, so
-        * equality here says we need one more line. We try to perform a quick
-        * comparison which is valid for the case where the logical line is
-        * the same, but otherwise fall back on a full TkTextIndexCmp.
-        */
-
-       if (((index.linePtr == indexPtr->linePtr)
-               && (index.byteIndex + byteCount > indexPtr->byteIndex))
-               || (dlPtr->logicalLinesMerged > 0
-               && TkTextIndexCmp(&nextLineStart, indexPtr) > 0)) {
-           /*
-            * It's on this display line.
-            */
-
-           if (xOffset != NULL) {
-               /*
-                * This call takes a byte index relative to the start of the
-                * current _display_ line, not logical line. We are about to
-                * overwrite indexPtr->byteIndex, so we must do this now.
-                */
-
-               *xOffset = DlineXOfIndex(textPtr, dlPtr,
-                       TkTextIndexCountBytes(textPtr, &dlPtr->index,
-                       indexPtr));
-           }
-           if (end) {
-               /*
-                * The index we want is one less than the number of bytes in
-                * the display line.
-                */
-
-               TkTextIndexBackBytes(textPtr, &nextLineStart, 1, indexPtr);
-           } else {
-               *indexPtr = index;
-           }
-           FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP);
-           return;
-       }
-
-       FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP);
-       index = nextLineStart;
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * CalculateDisplayLineHeight --
- *
- *     This function is invoked to recalculate the height of the particular
- *     display line which starts with the given index, whether that line is
- *     displayed or not.
- *
- *     This function does not, in itself, update any cached information about
- *     line heights. That should be done, where necessary, by its callers.
- *
- *     The behaviour of this function is _undefined_ if indexPtr is not
- *     currently at the beginning of a display line.
- *
- * Results:
- *     The number of vertical pixels used by the display line.
- *
- *     If 'byteCountPtr' is non-NULL, then returns in that pointer the number
- *     of byte indices on the given display line (which can be used to update
- *     indexPtr in a loop).
- *
- *     If 'mergedLinePtr' is non-NULL, then returns in that pointer the
- *     number of extra logical lines merged into the given display line.
- *
- * Side effects:
- *     The combination of 'LayoutDLine' and 'FreeDLines' seems like a rather
- *     time-consuming way of gathering the information we need, so this would
- *     be a good place to look to speed up the calculations. In particular
- *     these calls will map and unmap embedded windows respectively, which I
- *     would hope isn't exactly necessary!
- *
- *----------------------------------------------------------------------
- */
-
-static int
-CalculateDisplayLineHeight(
-    TkText *textPtr,           /* Widget record for text widget. */
-    const TkTextIndex *indexPtr,/* The index at the beginning of the display
-                                * line of interest. */
-    int *byteCountPtr,         /* NULL or used to return the number of byte
-                                * indices on the given display line. */
-    int *mergedLinePtr)                /* NULL or used to return if the given display
-                                * line merges with a following logical line
-                                * (because the eol is elided). */
-{
-    DLine *dlPtr;
-    int pixelHeight;
-
-    if (tkTextDebug) {
-        int oldtkTextDebug = tkTextDebug;
-        /*
-         * Check that the indexPtr we are given really is at the start of a
-         * display line. The gymnastics with tkTextDebug is to prevent
-         * failure of a test suite test, that checks that lines are rendered
-         * exactly once. TkTextFindDisplayLineEnd is used here for checking
-         * indexPtr but it calls LayoutDLine/FreeDLine which makes the
-         * counting wrong. The debug mode shall therefore be switched off
-         * when calling TkTextFindDisplayLineEnd.
-         */
-
-        TkTextIndex indexPtr2 = *indexPtr;
-        tkTextDebug = 0;
-        TkTextFindDisplayLineEnd(textPtr, &indexPtr2, 0, NULL);
-        tkTextDebug = oldtkTextDebug;
-        if (TkTextIndexCmp(&indexPtr2,indexPtr) != 0) {
-            Tcl_Panic("CalculateDisplayLineHeight called with bad indexPtr");
-        }
-    }
-
-    /*
-     * Special case for artificial last line. May be better to move this
-     * inside LayoutDLine.
-     */
-
-    if (indexPtr->byteIndex == 0
-           && TkBTreeNextLine(textPtr, indexPtr->linePtr) == NULL) {
-       if (byteCountPtr != NULL) {
-           *byteCountPtr = 0;
-       }
-       if (mergedLinePtr != NULL) {
-           *mergedLinePtr = 0;
-       }
-       return 0;
-    }
-
-    /*
-     * Layout, find the information we need and then free the display-line we
-     * laid-out. We must use 'FreeDLines' because it will actually call the
-     * relevant code to unmap any embedded windows which were mapped in the
-     * LayoutDLine call!
-     */
-
-    dlPtr = LayoutDLine(textPtr, indexPtr);
-    pixelHeight = dlPtr->height;
-    if (byteCountPtr != NULL) {
-       *byteCountPtr = dlPtr->byteCount;
-    }
-    if (mergedLinePtr != NULL) {
-       *mergedLinePtr = dlPtr->logicalLinesMerged;
-    }
-    FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP);
-
-    return pixelHeight;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextIndexYPixels --
- *
- *     This function is invoked to calculate the number of vertical pixels
- *     between the first index of the text widget and the given index. The
- *     range from first logical line to given logical line is determined
- *     using the cached values, and the range inside the given logical line
- *     is calculated on the fly.
- *
- * Results:
- *     The pixel distance between first pixel in the widget and the
- *     top of the index's current display line (could be zero).
- *
- * Side effects:
- *     Just those of 'CalculateDisplayLineHeight'.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkTextIndexYPixels(
-    TkText *textPtr,           /* Widget record for text widget. */
-    const TkTextIndex *indexPtr)/* The index of which we want the pixel
-                                * distance from top of logical line to top of
-                                * index. */
-{
-    int pixelHeight;
-    TkTextIndex index;
-    int alreadyStartOfLine = 1;
-
-    /*
-     * Find the index denoting the closest position being at the same time
-     * the start of a logical line above indexPtr and the start of a display
-     * line.
-     */
-
-    index = *indexPtr;
-    while (1) {
-        TkTextFindDisplayLineEnd(textPtr, &index, 0, NULL);
-        if (index.byteIndex == 0) {
-            break;
-        }
-        TkTextIndexBackBytes(textPtr, &index, 1, &index);
-        alreadyStartOfLine = 0;
-    }
-
-    pixelHeight = TkBTreePixelsTo(textPtr, index.linePtr);
-
-    /*
-     * Shortcut to avoid layout of a superfluous display line. We know there
-     * is nothing more to add up to the height if the index we were given was
-     * already on the first display line of a logical line.
-     */
-
-    if (alreadyStartOfLine) {
-        return pixelHeight;
-    }
-
-    /*
-     * Iterate through display lines, starting at the logical line belonging
-     * to index, adding up the pixel height of each such display line as we
-     * go along, until we go past 'indexPtr'.
-     */
-
-    while (1) {
-       int bytes, height, compare;
-
-       /*
-        * Currently this call doesn't have many side-effects. However, if in
-        * the future we change the code so there are side-effects (such as
-        * adjusting linePtr->pixelHeight), then the code might not quite work
-        * as intended, specifically the 'linePtr->pixelHeight == pixelHeight'
-        * test below this while loop.
-        */
-
-       height = CalculateDisplayLineHeight(textPtr, &index, &bytes, NULL);
-
-        TkTextIndexForwBytes(textPtr, &index, bytes, &index);
-
-        compare = TkTextIndexCmp(&index,indexPtr);
-        if (compare > 0) {
-           return pixelHeight;
-       }
-
-       if (height > 0) {
-           pixelHeight += height;
-       }
-
-        if (compare == 0) {
-           return pixelHeight;
-       }
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextUpdateOneLine --
- *
- *     This function is invoked to recalculate the height of a particular
- *     logical line, whether that line is displayed or not.
- *
- *     It must NEVER be called for the artificial last TkTextLine which is
- *     used internally for administrative purposes only. That line must
- *     retain its initial height of 0 otherwise the pixel height calculation
- *     maintained by the B-tree will be wrong.
- *
- * Results:
- *     The number of display lines in the logical line. This could be zero if
- *     the line is totally elided.
- *
- * Side effects:
- *     Line heights may be recalculated, and a timer to update the scrollbar
- *     may be installed. Also see the called function
- *     CalculateDisplayLineHeight for its side effects.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkTextUpdateOneLine(
-    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, at which
-                                * we wish to start (e.g. up to which we have
-                                * already calculated). On return this will be
-                                * set to the first index on the next line. */
-    int partialCalc)           /* Set to 1 if we are allowed to do partial
-                                * height calculations of long-lines. In this
-                                * case we'll only return what we know so
-                                * far. */
-{
-    TkTextIndex index;
-    int displayLines;
-    int mergedLines;
-
-    if (indexPtr == NULL) {
-       index.tree = textPtr->sharedTextPtr->tree;
-       index.linePtr = linePtr;
-       index.byteIndex = 0;
-       index.textPtr = NULL;
-       indexPtr = &index;
-       pixelHeight = 0;
-    }
-
-    /*
-     * CalculateDisplayLineHeight _must_ be called (below) with an index at
-     * the beginning of a display line. Force this to happen. This is needed
-     * when TkTextUpdateOneLine is called with a line that is merged with its
-     * previous line: the number of merged logical lines in a display line is
-     * calculated correctly only when CalculateDisplayLineHeight receives
-     * an index at the beginning of a display line. In turn this causes the
-     * merged lines to receive their correct zero pixel height in
-     * TkBTreeAdjustPixelHeight.
-     */
-
-    TkTextFindDisplayLineEnd(textPtr, indexPtr, 0, NULL);
-    linePtr = indexPtr->linePtr;
-
-    /*
-     * Iterate through all display-lines corresponding to the single logical
-     * line 'linePtr' (and lines merged into this line due to eol elision),
-     * adding up the pixel height of each such display line as we go along.
-     * The final total is, therefore, the total height of all display lines
-     * made up by the logical line 'linePtr' and subsequent logical lines
-     * merged into this line.
-     */
-
-    displayLines = 0;
-    mergedLines = 0;
-
-    while (1) {
-       int bytes, height, logicalLines;
-
-       /*
-        * Currently this call doesn't have many side-effects. However, if in
-        * the future we change the code so there are side-effects (such as
-        * adjusting linePtr->pixelHeight), then the code might not quite work
-        * as intended, specifically the 'linePtr->pixelHeight == pixelHeight'
-        * test below this while loop.
-        */
-
-        height = CalculateDisplayLineHeight(textPtr, indexPtr, &bytes,
-               &logicalLines);
-
-       if (height > 0) {
-           pixelHeight += height;
-           displayLines++;
-       }
-
-       mergedLines += logicalLines;
-
-       if (TkTextIndexForwBytes(textPtr, indexPtr, bytes, indexPtr)) {
-           break;
-       }
-
-        if (mergedLines == 0) {
-            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;
-            }
-        } else {
-            if (IsStartOfNotMergedLine(textPtr, indexPtr)) {
-                /*
-                 * We've ended a logical line.
-                 */
-
-                partialCalc = 0;
-                break;
-            }
-
-            /*
-             * We must still be on the same wrapped line, on a new logical
-             * line merged with the logical line 'linePtr'.
-             */
-        }
-       if (partialCalc && displayLines > 50 && mergedLines == 0) {
-           /*
-            * 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!
-            *
-            * If we have any merged lines, we must complete the full logical
-            * line layout here and now, because the partial-calculation code
-            * isn't designed to handle merged logical lines. Hence the
-            * 'mergedLines == 0' check.
-            */
-
-           break;
-       }
-    }
-
-    if (!partialCalc) {
-       int changed = 0;
-
-       /*
-        * Cancel any partial line height calculation state.
-        */
-
-       textPtr->dInfoPtr->metricEpoch = -1;
-
-       /*
-        * Mark the logical line as being up to date (caution: it isn't yet up
-        * to date, that will happen in TkBTreeAdjustPixelHeight just below).
-        */
-
-       TkBTreeLinePixelEpoch(textPtr, linePtr)
-               = textPtr->dInfoPtr->lineMetricUpdateEpoch;
-       if (TkBTreeLinePixelCount(textPtr, linePtr) != pixelHeight) {
-           changed = 1;
-       }
-
-       if (mergedLines > 0) {
-           int i = mergedLines;
-           TkTextLine *mergedLinePtr;
-
-           /*
-            * Loop over all merged logical lines, marking them up to date
-            * (again, the pixel count setting will actually happen in
-            * TkBTreeAdjustPixelHeight).
-            */
-
-           mergedLinePtr = linePtr;
-           while (i-- > 0) {
-               mergedLinePtr = TkBTreeNextLine(textPtr, mergedLinePtr);
-               TkBTreeLinePixelEpoch(textPtr, mergedLinePtr)
-                       = textPtr->dInfoPtr->lineMetricUpdateEpoch;
-               if (TkBTreeLinePixelCount(textPtr, mergedLinePtr) != 0) {
-                   changed = 1;
-               }
-           }
-       }
-
-       if (!changed) {
-           /*
-            * If there's nothing to change, then we can already return.
-            */
-
-           return displayLines;
-       }
-    }
-
-    /*
-     * 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(textPtr, linePtr, pixelHeight,
-           mergedLines);
-
-    if (tkTextDebug) {
-       char buffer[2 * TCL_INTEGER_SPACE + 1];
-
-       if (TkBTreeNextLine(textPtr, linePtr) == NULL) {
-           Tcl_Panic("Mustn't ever update line height of last artificial line");
-       }
-
-       sprintf(buffer, "%d %d", TkBTreeLinesTo(textPtr,linePtr), pixelHeight);
-       LOG("tk_textNumPixels", buffer);
-    }
-    if (textPtr->dInfoPtr->scrollbarTimer == NULL) {
-       textPtr->refCount++;
-       textPtr->dInfoPtr->scrollbarTimer = Tcl_CreateTimerHandler(200,
-               AsyncUpdateYScrollbar, textPtr);
-    }
-    return displayLines;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * DisplayText --
- *
- *     This function is invoked as a when-idle handler to update the display.
- *     It only redisplays the parts of the text widget that are out of date.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Information is redrawn on the screen.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-DisplayText(
-    ClientData clientData)     /* Information about widget. */
-{
-    register TkText *textPtr = clientData;
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    register DLine *dlPtr;
-    DLine *prevPtr;
-    Pixmap pixmap;
-    int maxHeight, borders;
-    int bottomY = 0;           /* Initialization needed only to stop compiler
-                                * warnings. */
-    Tcl_Interp *interp;
-
-
-    if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
-       /*
-        * The widget has been deleted.  Don't do anything.
-        */
-
-       return;
-    }
-
-    interp = textPtr->interp;
-    Tcl_Preserve(interp);
-
-    if (tkTextDebug) {
-       Tcl_SetVar2(interp, "tk_textRelayout", NULL, "", TCL_GLOBAL_ONLY);
-    }
-
-    if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
-       /*
-        * The widget has been deleted.  Don't do anything.
-        */
-
-       goto end;
-    }
-
-    if (!Tk_IsMapped(textPtr->tkwin) || (dInfoPtr->maxX <= dInfoPtr->x)
-           || (dInfoPtr->maxY <= dInfoPtr->y)) {
-       UpdateDisplayInfo(textPtr);
-       dInfoPtr->flags &= ~REDRAW_PENDING;
-       goto doScrollbars;
-    }
-    numRedisplays++;
-    if (tkTextDebug) {
-       Tcl_SetVar2(interp, "tk_textRedraw", NULL, "", TCL_GLOBAL_ONLY);
-    }
-
-    if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
-       /*
-        * The widget has been deleted. Don't do anything.
-        */
-
-       goto end;
-    }
-
-    /*
-     * Choose a new current item if that is needed (this could cause event
-     * handlers to be invoked, hence the preserve/release calls and the loop,
-     * since the handlers could conceivably necessitate yet another current
-     * item calculation). The tkwin check is because the whole window could go
-     * away in the Tcl_Release call.
-     */
-
-    while (dInfoPtr->flags & REPICK_NEEDED) {
-       textPtr->refCount++;
-       dInfoPtr->flags &= ~REPICK_NEEDED;
-       TkTextPickCurrent(textPtr, &textPtr->pickEvent);
-       if (--textPtr->refCount == 0) {
-           ckfree(textPtr);
-           goto end;
-       }
-       if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
-           goto end;
-       }
-    }
-
-    /*
-     * First recompute what's supposed to be displayed.
-     */
-
-    UpdateDisplayInfo(textPtr);
-    dInfoPtr->dLinesInvalidated = 0;
-
-    /*
-     * See if it's possible to bring some parts of the screen up-to-date by
-     * scrolling (copying from other parts of the screen). We have to be
-     * particularly careful with the top and bottom lines of the display,
-     * since these may only be partially visible and therefore not helpful for
-     * some scrolling purposes.
-     */
-
-    for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) {
-       register DLine *dlPtr2;
-       int offset, height, y, oldY;
-       TkRegion damageRgn;
-
-       /*
-        * These tests are, in order:
-        *
-        * 1. If the line is already marked as invalid
-        * 2. If the line hasn't moved
-        * 3. If the line overlaps the bottom of the window and we are
-        *    scrolling up.
-        * 4. If the line overlaps the top of the window and we are scrolling
-        *    down.
-        *
-        * If any of these tests are true, then we can't scroll this line's
-        * part of the display.
-        *
-        * Note that even if tests 3 or 4 aren't true, we may be able to
-        * scroll the line, but we still need to be sure to call embedded
-        * window display procs on top and bottom lines if they have any
-        * portion non-visible (see below).
-        */
-
-       if ((dlPtr->flags & OLD_Y_INVALID)
-               || (dlPtr->y == dlPtr->oldY)
-               || (((dlPtr->oldY + dlPtr->height) > dInfoPtr->maxY)
-                   && (dlPtr->y < dlPtr->oldY))
-               || ((dlPtr->oldY < dInfoPtr->y) && (dlPtr->y > dlPtr->oldY))) {
-           continue;
-       }
-
-       /*
-        * This line is already drawn somewhere in the window so it only needs
-        * to be copied to its new location. See if there's a group of lines
-        * that can all be copied together.
-        */
-
-       offset = dlPtr->y - dlPtr->oldY;
-       height = dlPtr->height;
-       y = dlPtr->y;
-       for (dlPtr2 = dlPtr->nextPtr; dlPtr2 != NULL;
-               dlPtr2 = dlPtr2->nextPtr) {
-           if ((dlPtr2->flags & OLD_Y_INVALID)
-                   || ((dlPtr2->oldY + offset) != dlPtr2->y)
-                   || ((dlPtr2->oldY + dlPtr2->height) > dInfoPtr->maxY)) {
-               break;
-           }
-           height += dlPtr2->height;
-       }
-
-       /*
-        * Reduce the height of the area being copied if necessary to avoid
-        * overwriting the border area.
-        */
-
-       if ((y + height) > dInfoPtr->maxY) {
-           height = dInfoPtr->maxY - y;
-       }
-       oldY = dlPtr->oldY;
-       if (y < dInfoPtr->y) {
-           /*
-            * Adjust if the area being copied is going to overwrite the top
-            * border of the window (so the top line is only half onscreen).
-            */
-
-           int y_off = dInfoPtr->y - dlPtr->y;
-           height -= y_off;
-           oldY += y_off;
-           y = dInfoPtr->y;
-       }
-
-       /*
-        * Update the lines we are going to scroll to show that they have been
-        * copied.
-        */
-
-       while (1) {
-           /*
-            * The DLine already has OLD_Y_INVALID cleared.
-            */
-
-           dlPtr->oldY = dlPtr->y;
-           if (dlPtr->nextPtr == dlPtr2) {
-               break;
-           }
-           dlPtr = dlPtr->nextPtr;
-       }
-
-       /*
-        * Scan through the lines following the copied ones to see if we are
-        * going to overwrite them with the copy operation. If so, mark them
-        * for redisplay.
-        */
-
-       for ( ; dlPtr2 != NULL; dlPtr2 = dlPtr2->nextPtr) {
-           if ((!(dlPtr2->flags & OLD_Y_INVALID))
-                   && ((dlPtr2->oldY + dlPtr2->height) > y)
-                   && (dlPtr2->oldY < (y + height))) {
-               dlPtr2->flags |= OLD_Y_INVALID;
-           }
-       }
-
-       /*
-        * Now scroll the lines. This may generate damage which we handle by
-        * calling TextInvalidateRegion to mark the display blocks as stale.
-        */
-
-       damageRgn = TkCreateRegion();
-       if (TkScrollWindow(textPtr->tkwin, dInfoPtr->scrollGC, dInfoPtr->x,
-               oldY, dInfoPtr->maxX-dInfoPtr->x, height, 0, y-oldY,
-               damageRgn)) {
-           TextInvalidateRegion(textPtr, damageRgn);
-
-       }
-       numCopies++;
-       TkDestroyRegion(damageRgn);
-    }
-
-    /*
-     * Clear the REDRAW_PENDING flag here. This is actually pretty tricky. We
-     * want to wait until *after* doing the scrolling, since that could
-     * generate more areas to redraw and don't want to reschedule a redisplay
-     * for them. On the other hand, we can't wait until after all the
-     * redisplaying, because the act of redisplaying could actually generate
-     * more redisplays (e.g. in the case of a nested window with event
-     * bindings triggered by redisplay).
-     */
-
-    dInfoPtr->flags &= ~REDRAW_PENDING;
-
-    /*
-     * Redraw the borders if that's needed.
-     */
-
-    if (dInfoPtr->flags & REDRAW_BORDERS) {
-       if (tkTextDebug) {
-           LOG("tk_textRedraw", "borders");
-       }
-
-       if (textPtr->tkwin == NULL) {
-           /*
-            * The widget has been deleted. Don't do anything.
-            */
-
-           goto end;
-       }
-
-       Tk_Draw3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin),
-               textPtr->border, textPtr->highlightWidth,
-               textPtr->highlightWidth,
-               Tk_Width(textPtr->tkwin) - 2*textPtr->highlightWidth,
-               Tk_Height(textPtr->tkwin) - 2*textPtr->highlightWidth,
-               textPtr->borderWidth, textPtr->relief);
-       if (textPtr->highlightWidth != 0) {
-           GC fgGC, bgGC;
-
-           bgGC = Tk_GCForColor(textPtr->highlightBgColorPtr,
-                   Tk_WindowId(textPtr->tkwin));
-           if (textPtr->flags & GOT_FOCUS) {
-               fgGC = Tk_GCForColor(textPtr->highlightColorPtr,
-                       Tk_WindowId(textPtr->tkwin));
-               TkpDrawHighlightBorder(textPtr->tkwin, fgGC, bgGC,
-                       textPtr->highlightWidth, Tk_WindowId(textPtr->tkwin));
-           } else {
-               TkpDrawHighlightBorder(textPtr->tkwin, bgGC, bgGC,
-                       textPtr->highlightWidth, Tk_WindowId(textPtr->tkwin));
-           }
-       }
-       borders = textPtr->borderWidth + textPtr->highlightWidth;
-       if (textPtr->padY > 0) {
-           Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin),
-                   textPtr->border, borders, borders,
-                   Tk_Width(textPtr->tkwin) - 2*borders, textPtr->padY,
-                   0, TK_RELIEF_FLAT);
-           Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin),
-                   textPtr->border, borders,
-                   Tk_Height(textPtr->tkwin) - borders - textPtr->padY,
-                   Tk_Width(textPtr->tkwin) - 2*borders,
-                   textPtr->padY, 0, TK_RELIEF_FLAT);
-       }
-       if (textPtr->padX > 0) {
-           Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin),
-                   textPtr->border, borders, borders + textPtr->padY,
-                   textPtr->padX,
-                   Tk_Height(textPtr->tkwin) - 2*borders -2*textPtr->padY,
-                   0, TK_RELIEF_FLAT);
-           Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin),
-                   textPtr->border,
-                   Tk_Width(textPtr->tkwin) - borders - textPtr->padX,
-                   borders + textPtr->padY, textPtr->padX,
-                   Tk_Height(textPtr->tkwin) - 2*borders -2*textPtr->padY,
-                   0, TK_RELIEF_FLAT);
-       }
-       dInfoPtr->flags &= ~REDRAW_BORDERS;
-    }
-
-    /*
-     * Now we have to redraw the lines that couldn't be updated by scrolling.
-     * First, compute the height of the largest line and allocate an off-
-     * screen pixmap to use for double-buffered displays.
-     */
-
-    maxHeight = -1;
-    for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL;
-           dlPtr = dlPtr->nextPtr) {
-       if ((dlPtr->height > maxHeight) &&
-               ((dlPtr->flags&OLD_Y_INVALID) || (dlPtr->oldY != dlPtr->y))) {
-           maxHeight = dlPtr->height;
-       }
-       bottomY = dlPtr->y + dlPtr->height;
-    }
-
-    /*
-     * There used to be a line here which restricted 'maxHeight' to be no
-     * larger than 'dInfoPtr->maxY', but this is incorrect for the case where
-     * individual lines may be taller than the widget _and_ we have smooth
-     * scrolling. What we can do is restrict maxHeight to be no larger than
-     * 'dInfoPtr->maxY + dInfoPtr->topPixelOffset'.
-     */
-
-    if (maxHeight > (dInfoPtr->maxY + dInfoPtr->topPixelOffset)) {
-       maxHeight = (dInfoPtr->maxY + dInfoPtr->topPixelOffset);
-    }
-
-    if (maxHeight > 0) {
-#ifndef TK_NO_DOUBLE_BUFFERING
-       pixmap = Tk_GetPixmap(Tk_Display(textPtr->tkwin),
-               Tk_WindowId(textPtr->tkwin), Tk_Width(textPtr->tkwin),
-               maxHeight, Tk_Depth(textPtr->tkwin));
-#else
-       pixmap = Tk_WindowId(textPtr->tkwin);
-#endif /* TK_NO_DOUBLE_BUFFERING */
-       for (prevPtr = NULL, dlPtr = textPtr->dInfoPtr->dLinePtr;
-               (dlPtr != NULL) && (dlPtr->y < dInfoPtr->maxY);
-               prevPtr = dlPtr, dlPtr = dlPtr->nextPtr) {
-           if (dlPtr->chunkPtr == NULL) {
-               continue;
-           }
-           if ((dlPtr->flags & OLD_Y_INVALID) || dlPtr->oldY != dlPtr->y) {
-               if (tkTextDebug) {
-                   char string[TK_POS_CHARS];
-
-                   TkTextPrintIndex(textPtr, &dlPtr->index, string);
-                   LOG("tk_textRedraw", string);
-               }
-               DisplayDLine(textPtr, dlPtr, prevPtr, pixmap);
-               if (dInfoPtr->dLinesInvalidated) {
-#ifndef TK_NO_DOUBLE_BUFFERING
-                   Tk_FreePixmap(Tk_Display(textPtr->tkwin), pixmap);
-#endif /* TK_NO_DOUBLE_BUFFERING */
-                   return;
-               }
-               dlPtr->oldY = dlPtr->y;
-               dlPtr->flags &= ~(NEW_LAYOUT | OLD_Y_INVALID);
-           } else if (dlPtr->chunkPtr != NULL && ((dlPtr->y < 0)
-                   || (dlPtr->y + dlPtr->height > dInfoPtr->maxY))) {
-               register TkTextDispChunk *chunkPtr;
-
-               /*
-                * It's the first or last DLine which are also overlapping the
-                * top or bottom of the window, but we decided above it wasn't
-                * necessary to display them (we were able to update them by
-                * scrolling). This is fine, except that if the lines contain
-                * any embedded windows, we must still call the display proc
-                * on them because they might need to be unmapped or they
-                * might need to be moved to reflect their new position.
-                * Otherwise, everything else moves, but the embedded window
-                * doesn't!
-                *
-                * So, we loop through all the chunks, calling the display
-                * proc of embedded windows only.
-                */
-
-               for (chunkPtr = dlPtr->chunkPtr; (chunkPtr != NULL);
-                       chunkPtr = chunkPtr->nextPtr) {
-                   int x;
-                   if (chunkPtr->displayProc != TkTextEmbWinDisplayProc) {
-                       continue;
-                   }
-                   x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curXPixelOffset;
-                   if ((x + chunkPtr->width <= 0) || (x >= dInfoPtr->maxX)) {
-                       /*
-                        * Note: we have to call the displayProc even for
-                        * chunks that are off-screen. This is needed, for
-                        * example, so that embedded windows can be unmapped
-                        * in this case. Display the chunk at a coordinate
-                        * that can be clearly identified by the displayProc
-                        * as being off-screen to the left (the displayProc
-                        * may not be able to tell if something is off to the
-                        * right).
-                        */
-
-                       x = -chunkPtr->width;
-                   }
-                   TkTextEmbWinDisplayProc(textPtr, chunkPtr, x,
-                           dlPtr->spaceAbove,
-                           dlPtr->height-dlPtr->spaceAbove-dlPtr->spaceBelow,
-                           dlPtr->baseline - dlPtr->spaceAbove, NULL,
-                           (Drawable) None, dlPtr->y + dlPtr->spaceAbove);
-               }
-
-           }
-       }
-#ifndef TK_NO_DOUBLE_BUFFERING
-       Tk_FreePixmap(Tk_Display(textPtr->tkwin), pixmap);
-#endif /* TK_NO_DOUBLE_BUFFERING */
-    }
-
-    /*
-     * See if we need to refresh the part of the window below the last line of
-     * text (if there is any such area). Refresh the padding area on the left
-     * too, since the insertion cursor might have been displayed there
-     * previously).
-     */
-
-    if (dInfoPtr->topOfEof > dInfoPtr->maxY) {
-       dInfoPtr->topOfEof = dInfoPtr->maxY;
-    }
-    if (bottomY < dInfoPtr->topOfEof) {
-       if (tkTextDebug) {
-           LOG("tk_textRedraw", "eof");
-       }
-
-       if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
-           /*
-            * The widget has been deleted. Don't do anything.
-            */
-
-           goto end;
-       }
-
-       Tk_Fill3DRectangle(textPtr->tkwin, Tk_WindowId(textPtr->tkwin),
-               textPtr->border, dInfoPtr->x - textPtr->padX, bottomY,
-               dInfoPtr->maxX - (dInfoPtr->x - textPtr->padX),
-               dInfoPtr->topOfEof-bottomY, 0, TK_RELIEF_FLAT);
-    }
-    dInfoPtr->topOfEof = bottomY;
-
-    /*
-     * Update the vertical scrollbar, if there is one. Note: it's important to
-     * clear REDRAW_PENDING here, just in case the scroll function does
-     * something that requires redisplay.
-     */
-
-  doScrollbars:
-    if (textPtr->flags & UPDATE_SCROLLBARS) {
-       textPtr->flags &= ~UPDATE_SCROLLBARS;
-       if (textPtr->yScrollCmd != NULL) {
-           GetYView(textPtr->interp, textPtr, 1);
-       }
-
-       if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
-           /*
-            * The widget has been deleted. Don't do anything.
-            */
-
-           goto end;
-       }
-
-       /*
-        * Update the horizontal scrollbar, if any.
-        */
-
-       if (textPtr->xScrollCmd != NULL) {
-           GetXView(textPtr->interp, textPtr, 1);
-       }
-    }
-
-  end:
-    Tcl_Release(interp);
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextEventuallyRepick --
- *
- *     This function is invoked whenever something happens that could change
- *     the current character or the tags associated with it.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     A repick is scheduled as an idle handler.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextEventuallyRepick(
-    TkText *textPtr)           /* Widget record for text widget. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-
-    dInfoPtr->flags |= REPICK_NEEDED;
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       dInfoPtr->flags |= REDRAW_PENDING;
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextRedrawRegion --
- *
- *     This function is invoked to schedule a redisplay for a given region of
- *     a text widget. The redisplay itself may not occur immediately: it's
- *     scheduled as a when-idle handler.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Information will eventually be redrawn on the screen.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextRedrawRegion(
-    TkText *textPtr,           /* Widget record for text widget. */
-    int x, int y,              /* Coordinates of upper-left corner of area to
-                                * be redrawn, in pixels relative to textPtr's
-                                * window. */
-    int width, int height)     /* Width and height of area to be redrawn. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    TkRegion damageRgn = TkCreateRegion();
-    XRectangle rect;
-
-    rect.x = x;
-    rect.y = y;
-    rect.width = width;
-    rect.height = height;
-    TkUnionRectWithRegion(&rect, damageRgn, damageRgn);
-
-    TextInvalidateRegion(textPtr, damageRgn);
-
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       dInfoPtr->flags |= REDRAW_PENDING;
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-    TkDestroyRegion(damageRgn);
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TextInvalidateRegion --
- *
- *     Mark a region of text as invalid.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Updates the display information for the text widget.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-TextInvalidateRegion(
-    TkText *textPtr,           /* Widget record for text widget. */
-    TkRegion region)           /* Region of area to redraw. */
-{
-    register DLine *dlPtr;
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    int maxY, inset;
-    XRectangle rect;
-
-    /*
-     * Find all lines that overlap the given region and mark them for
-     * redisplay.
-     */
-
-    TkClipBox(region, &rect);
-    maxY = rect.y + rect.height;
-    for (dlPtr = dInfoPtr->dLinePtr; dlPtr != NULL;
-           dlPtr = dlPtr->nextPtr) {
-       if ((!(dlPtr->flags & OLD_Y_INVALID))
-               && (TkRectInRegion(region, rect.x, dlPtr->y,
-               rect.width, (unsigned int) dlPtr->height) != RectangleOut)) {
-           dlPtr->flags |= OLD_Y_INVALID;
-       }
-    }
-    if (dInfoPtr->topOfEof < maxY) {
-       dInfoPtr->topOfEof = maxY;
-    }
-
-    /*
-     * Schedule the redisplay operation if there isn't one already scheduled.
-     */
-
-    inset = textPtr->borderWidth + textPtr->highlightWidth;
-    if ((rect.x < (inset + textPtr->padX))
-           || (rect.y < (inset + textPtr->padY))
-           || ((int) (rect.x + rect.width) > (Tk_Width(textPtr->tkwin)
-                   - inset - textPtr->padX))
-           || (maxY > (Tk_Height(textPtr->tkwin) - inset - textPtr->padY))) {
-       dInfoPtr->flags |= REDRAW_BORDERS;
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextChanged, TextChanged --
- *
- *     This function is invoked when info in a text widget is about to be
- *     modified in a way that changes how it is displayed (e.g. characters
- *     were inserted or deleted, or tag information was changed). This
- *     function must be called *before* a change is made, so that indexes in
- *     the display information are still valid.
- *
- *     Note: if the range of indices may change geometry as well as simply
- *     requiring redisplay, then the caller should also call
- *     TkTextInvalidateLineMetrics.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The range of character between index1Ptr (inclusive) and index2Ptr
- *     (exclusive) will be redisplayed at some point in the future (the
- *     actual redisplay is scheduled as a when-idle handler).
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextChanged(
-    TkSharedText *sharedTextPtr,/* Shared widget section, or NULL. */
-    TkText *textPtr,           /* Widget record for text widget, or NULL. */
-    const TkTextIndex*index1Ptr,/* Index of first character to redisplay. */
-    const TkTextIndex*index2Ptr)/* Index of character just after last one to
-                                * redisplay. */
-{
-    if (sharedTextPtr == NULL) {
-       TextChanged(textPtr, index1Ptr, index2Ptr);
-    } else {
-       textPtr = sharedTextPtr->peers;
-       while (textPtr != NULL) {
-           TextChanged(textPtr, index1Ptr, index2Ptr);
-           textPtr = textPtr->next;
-       }
-    }
-}
-\f
-static void
-TextChanged(
-    TkText *textPtr,           /* Widget record for text widget, or NULL. */
-    const TkTextIndex*index1Ptr,/* Index of first character to redisplay. */
-    const TkTextIndex*index2Ptr)/* Index of character just after last one to
-                                * redisplay. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    DLine *firstPtr, *lastPtr;
-    TkTextIndex rounded;
-    TkTextLine *linePtr;
-    int notBegin;
-
-    /*
-     * Schedule both a redisplay and a recomputation of display information.
-     * It's done here rather than the end of the function for two reasons:
-     *
-     * 1. If there are no display lines to update we'll want to return
-     *   immediately, well before the end of the function.
-     * 2. It's important to arrange for the redisplay BEFORE calling
-     *   FreeDLines. The reason for this is subtle and has to do with
-     *   embedded windows. The chunk delete function for an embedded window
-     *   will schedule an idle handler to unmap the window. However, we want
-     *   the idle handler for redisplay to be called first, so that it can
-     *   put the embedded window back on the screen again (if appropriate).
-     *   This will prevent the window from ever being unmapped, and thereby
-     *   avoid flashing.
-     */
-
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-    dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED;
-
-    /*
-     * Find the DLines corresponding to index1Ptr and index2Ptr. There is one
-     * tricky thing here, which is that we have to relayout in units of whole
-     * text lines: This is necessary because the indices stored in the display
-     * lines will no longer be valid. It's also needed because any edit could
-     * change the way lines wrap.
-     * To relayout in units of whole text (logical) lines, round index1Ptr
-     * back to the beginning of its text line (or, if this line start is
-     * elided, to the beginning of the text line that starts the display line
-     * it is included in), and include all the display lines after index2Ptr,
-     * up to the end of its text line (or, if this line end is elided, up to
-     * the end of the first non elided text line after this line end).
-     */
-
-    rounded = *index1Ptr;
-    rounded.byteIndex = 0;
-    notBegin = 0;
-    while (!IsStartOfNotMergedLine(textPtr, &rounded) && notBegin) {
-        notBegin = !TkTextIndexBackBytes(textPtr, &rounded, 1, &rounded);
-        rounded.byteIndex = 0;
-    }
-
-    /*
-     * 'rounded' now points to the start of a display line as well as the
-     * real (non elided) start of a logical line, and this index is the
-     * closest before index1Ptr.
-     */
-
-    firstPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &rounded);
-
-    if (firstPtr == NULL) {
-        /*
-         * index1Ptr pertains to no display line, i.e this index is after
-         * the last display line. Since index2Ptr is after index1Ptr, there
-         * is no display line to free/redisplay and we can return early.
-         */
-
-       return;
-    }
-
-    rounded = *index2Ptr;
-    linePtr = index2Ptr->linePtr;
-    do {
-        linePtr = TkBTreeNextLine(textPtr, linePtr);
-        if (linePtr == NULL) {
-            break;
-        }
-        rounded.linePtr = linePtr;
-        rounded.byteIndex = 0;
-    } while (!IsStartOfNotMergedLine(textPtr, &rounded));
-
-    if (linePtr == NULL) {
-        lastPtr = NULL;
-    } else {
-        /*
-         * 'rounded' now points to the start of a display line as well as the
-         * start of a logical line not merged with its previous line, and
-         * this index is the closest after index2Ptr.
-         */
-
-        lastPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &rounded);
-
-        /*
-         * At least one display line is supposed to change. This makes the
-         * redisplay OK in case the display line we expect to get here was
-         * unlinked by a previous call to TkTextChanged and the text widget
-         * did not update before reaching this point. This happens for
-         * instance when moving the cursor up one line.
-         * Note that lastPtr != NULL here, otherwise we would have returned
-         * earlier when we tested for firstPtr being NULL.
-         */
-
-        if (lastPtr == firstPtr) {
-            lastPtr = lastPtr->nextPtr;
-        }
-    }
-
-    /*
-     * Delete all the DLines from firstPtr up to but not including lastPtr.
-     */
-
-    FreeDLines(textPtr, firstPtr, lastPtr, DLINE_UNLINK);
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextRedrawTag, TextRedrawTag --
- *
- *     This function is invoked to request a redraw of all characters in a
- *     given range that have a particular tag on or off. It's called, for
- *     example, when tag options change.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Information on the screen may be redrawn, and the layout of the screen
- *     may change.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextRedrawTag(
-    TkSharedText *sharedTextPtr,/* Shared widget section, or NULL. */
-    TkText *textPtr,           /* Widget record for text widget. */
-    TkTextIndex *index1Ptr,    /* First character in range to consider for
-                                * redisplay. NULL means start at beginning of
-                                * text. */
-    TkTextIndex *index2Ptr,    /* Character just after last one to consider
-                                * for redisplay. NULL means process all the
-                                * characters in the text. */
-    TkTextTag *tagPtr,         /* Information about tag. */
-    int withTag)               /* 1 means redraw characters that have the
-                                * tag, 0 means redraw those without. */
-{
-    if (sharedTextPtr == NULL) {
-       TextRedrawTag(textPtr, index1Ptr, index2Ptr, tagPtr, withTag);
-    } else {
-       textPtr = sharedTextPtr->peers;
-       while (textPtr != NULL) {
-           TextRedrawTag(textPtr, index1Ptr, index2Ptr, tagPtr, withTag);
-           textPtr = textPtr->next;
-       }
-    }
-}
-\f
-static void
-TextRedrawTag(
-    TkText *textPtr,           /* Widget record for text widget. */
-    TkTextIndex *index1Ptr,    /* First character in range to consider for
-                                * redisplay. NULL means start at beginning of
-                                * text. */
-    TkTextIndex *index2Ptr,    /* Character just after last one to consider
-                                * for redisplay. NULL means process all the
-                                * characters in the text. */
-    TkTextTag *tagPtr,         /* Information about tag. */
-    int withTag)               /* 1 means redraw characters that have the
-                                * tag, 0 means redraw those without. */
-{
-    register DLine *dlPtr;
-    DLine *endPtr;
-    int tagOn;
-    TkTextSearch search;
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    TkTextIndex *curIndexPtr;
-    TkTextIndex endOfText, *endIndexPtr;
-
-    /*
-     * Invalidate the pixel calculation of all lines in the given range. This
-     * may be a bit over-aggressive, so we could consider more subtle
-     * techniques here in the future. In particular, when we create a tag for
-     * the first time with '.t tag configure foo -font "Arial 20"', say, even
-     * though that obviously can't apply to anything at all (the tag didn't
-     * exist a moment ago), we invalidate every single line in the widget.
-     */
-
-    if (tagPtr->affectsDisplayGeometry) {
-       TkTextLine *startLine, *endLine;
-       int lineCount;
-
-       if (index2Ptr == NULL) {
-           endLine = NULL;
-           lineCount = TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr);
-       } else {
-           endLine = index2Ptr->linePtr;
-           lineCount = TkBTreeLinesTo(textPtr, endLine);
-       }
-       if (index1Ptr == NULL) {
-           startLine = NULL;
-       } else {
-           startLine = index1Ptr->linePtr;
-           lineCount -= TkBTreeLinesTo(textPtr, startLine);
-       }
-       TkTextInvalidateLineMetrics(NULL, textPtr, startLine, lineCount,
-               TK_TEXT_INVALIDATE_ONLY);
-    }
-
-    /*
-     * Round up the starting position if it's before the first line visible on
-     * the screen (we only care about what's on the screen).
-     */
-
-    dlPtr = dInfoPtr->dLinePtr;
-    if (dlPtr == NULL) {
-       return;
-    }
-    if ((index1Ptr == NULL) || (TkTextIndexCmp(&dlPtr->index, index1Ptr)>0)) {
-       index1Ptr = &dlPtr->index;
-    }
-
-    /*
-     * Set the stopping position if it wasn't specified.
-     */
-
-    if (index2Ptr == NULL) {
-       int lastLine = TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr);
-
-       index2Ptr = TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr,
-               lastLine, 0, &endOfText);
-    }
-
-    /*
-     * Initialize a search through all transitions on the tag, starting with
-     * the first transition where the tag's current state is different from
-     * what it will eventually be.
-     */
-
-    TkBTreeStartSearch(index1Ptr, index2Ptr, tagPtr, &search);
-
-    /*
-     * Make our own curIndex because at this point search.curIndex may not
-     * equal index1Ptr->curIndex in the case the first tag toggle comes after
-     * index1Ptr (See the use of FindTagStart in TkBTreeStartSearch).
-     */
-
-    curIndexPtr = index1Ptr;
-    tagOn = TkBTreeCharTagged(index1Ptr, tagPtr);
-    if (tagOn != withTag) {
-       if (!TkBTreeNextTag(&search)) {
-           return;
-       }
-       curIndexPtr = &search.curIndex;
-    }
-
-    /*
-     * Schedule a redisplay and layout recalculation if they aren't already
-     * pending. This has to be done before calling FreeDLines, for the reason
-     * given in TkTextChanged.
-     */
-
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-    dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED;
-
-    /*
-     * Each loop through the loop below is for one range of characters where
-     * the tag's current state is different than its eventual state. At the
-     * top of the loop, search contains information about the first character
-     * in the range.
-     */
-
-    while (1) {
-       /*
-        * Find the first DLine structure in the range. Note: if the desired
-        * character isn't the first in its text line, then look for the
-        * character just before it instead. This is needed to handle the case
-        * where the first character of a wrapped display line just got
-        * smaller, so that it now fits on the line before: need to relayout
-        * the line containing the previous character.
-        */
-
-       if (IsStartOfNotMergedLine(textPtr, curIndexPtr)) {
-           dlPtr = FindDLine(textPtr, dlPtr, curIndexPtr);
-       } else {
-           TkTextIndex tmp = *curIndexPtr;
-
-            TkTextIndexBackBytes(textPtr, &tmp, 1, &tmp);
-           dlPtr = FindDLine(textPtr, dlPtr, &tmp);
-       }
-       if (dlPtr == NULL) {
-           break;
-       }
-
-       /*
-        * Find the first DLine structure that's past the end of the range.
-        */
-
-       if (!TkBTreeNextTag(&search)) {
-           endIndexPtr = index2Ptr;
-       } else {
-           curIndexPtr = &search.curIndex;
-           endIndexPtr = curIndexPtr;
-       }
-       endPtr = FindDLine(textPtr, dlPtr, endIndexPtr);
-       if ((endPtr != NULL)
-                && (TkTextIndexCmp(&endPtr->index,endIndexPtr) < 0)) {
-           endPtr = endPtr->nextPtr;
-       }
-
-       /*
-        * Delete all of the display lines in the range, so that they'll be
-        * re-layed out and redrawn.
-        */
-
-       FreeDLines(textPtr, dlPtr, endPtr, DLINE_UNLINK);
-       dlPtr = endPtr;
-
-       /*
-        * Find the first text line in the next range.
-        */
-
-       if (!TkBTreeNextTag(&search)) {
-           break;
-       }
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextRelayoutWindow --
- *
- *     This function is called when something has happened that invalidates
- *     the whole layout of characters on the screen, such as a change in a
- *     configuration option for the overall text widget or a change in the
- *     window size. It causes all display information to be recomputed and
- *     the window to be redrawn.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     All the display information will be recomputed for the window and the
- *     window will be redrawn.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextRelayoutWindow(
-    TkText *textPtr,           /* Widget record for text widget. */
-    int mask)                  /* OR'd collection of bits showing what has
-                                * changed. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    GC newGC;
-    XGCValues gcValues;
-
-    /*
-     * Schedule the window redisplay. See TkTextChanged for the reason why
-     * this has to be done before any calls to FreeDLines.
-     */
-
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-    dInfoPtr->flags |= REDRAW_PENDING|REDRAW_BORDERS|DINFO_OUT_OF_DATE
-           |REPICK_NEEDED;
-
-    /*
-     * (Re-)create the graphics context for drawing the traversal highlight.
-     */
-
-    gcValues.graphics_exposures = False;
-    newGC = Tk_GetGC(textPtr->tkwin, GCGraphicsExposures, &gcValues);
-    if (dInfoPtr->copyGC != None) {
-       Tk_FreeGC(textPtr->display, dInfoPtr->copyGC);
-    }
-    dInfoPtr->copyGC = newGC;
-
-    /*
-     * Throw away all the current layout information.
-     */
-
-    FreeDLines(textPtr, dInfoPtr->dLinePtr, NULL, DLINE_UNLINK);
-    dInfoPtr->dLinePtr = NULL;
-
-    /*
-     * Recompute some overall things for the layout. Even if the window gets
-     * very small, pretend that there's at least one pixel of drawing space in
-     * it.
-     */
-
-    if (textPtr->highlightWidth < 0) {
-       textPtr->highlightWidth = 0;
-    }
-    dInfoPtr->x = textPtr->highlightWidth + textPtr->borderWidth
-           + textPtr->padX;
-    dInfoPtr->y = textPtr->highlightWidth + textPtr->borderWidth
-           + textPtr->padY;
-    dInfoPtr->maxX = Tk_Width(textPtr->tkwin) - textPtr->highlightWidth
-           - textPtr->borderWidth - textPtr->padX;
-    if (dInfoPtr->maxX <= dInfoPtr->x) {
-       dInfoPtr->maxX = dInfoPtr->x + 1;
-    }
-
-    /*
-     * This is the only place where dInfoPtr->maxY is set.
-     */
-
-    dInfoPtr->maxY = Tk_Height(textPtr->tkwin) - textPtr->highlightWidth
-           - textPtr->borderWidth - textPtr->padY;
-    if (dInfoPtr->maxY <= dInfoPtr->y) {
-       dInfoPtr->maxY = dInfoPtr->y + 1;
-    }
-    dInfoPtr->topOfEof = dInfoPtr->maxY;
-
-    /*
-     * If the upper-left character isn't the first in a line, recompute it.
-     * This is necessary because a change in the window's size or options
-     * could change the way lines wrap.
-     */
-
-    if (!IsStartOfNotMergedLine(textPtr, &textPtr->topIndex)) {
-       TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
-    }
-
-    /*
-     * Invalidate cached scrollbar positions, so that scrollbars sliders will
-     * be udpated.
-     */
-
-    dInfoPtr->xScrollFirst = dInfoPtr->xScrollLast = -1;
-    dInfoPtr->yScrollFirst = dInfoPtr->yScrollLast = -1;
-
-    if (mask & TK_TEXT_LINE_GEOMETRY) {
-       /*
-        * Set up line metric recalculation.
-        *
-        * Avoid the special zero value, since that is used to mark individual
-        * lines as being out of date.
-        */
-
-       if ((++dInfoPtr->lineMetricUpdateEpoch) == 0) {
-           dInfoPtr->lineMetricUpdateEpoch++;
-       }
-
-       dInfoPtr->currentMetricUpdateLine = -1;
-
-       /*
-        * Also cancel any partial line-height calculations (for long-wrapped
-        * lines) in progress.
-        */
-
-       dInfoPtr->metricEpoch = -1;
-
-       if (dInfoPtr->lineUpdateTimer == NULL) {
-           textPtr->refCount++;
-           dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1,
-                   AsyncUpdateLineMetrics, textPtr);
-       }
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextSetYView --
- *
- *     This function is called to specify what lines are to be displayed in a
- *     text widget.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The display will (eventually) be updated so that the position given by
- *     "indexPtr" is visible on the screen at the position determined by
- *     "pickPlace".
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextSetYView(
-    TkText *textPtr,           /* Widget record for text widget. */
-    TkTextIndex *indexPtr,     /* Position that is to appear somewhere in the
-                                * view. */
-    int pickPlace)             /* 0 means the given index must appear exactly
-                                * at the top of the screen. TK_TEXT_PICKPLACE
-                                * (-1) means we get to pick where it appears:
-                                * minimize screen motion or else display line
-                                * at center of screen. TK_TEXT_NOPIXELADJUST
-                                * (-2) indicates to make the given index the
-                                * top line, but if it is already the top
-                                * line, don't nudge it up or down by a few
-                                * pixels just to make sure it is entirely
-                                * displayed. Positive numbers indicate the
-                                * number of pixels of the index's line which
-                                * are to be off the top of the screen. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    register DLine *dlPtr;
-    int bottomY, close, lineIndex;
-    TkTextIndex tmpIndex, rounded;
-    int lineHeight;
-
-    /*
-     * If the specified position is the extra line at the end of the text,
-     * round it back to the last real line.
-     */
-
-    lineIndex = TkBTreeLinesTo(textPtr, indexPtr->linePtr);
-    if (lineIndex == TkBTreeNumLines(indexPtr->tree, textPtr)) {
-       TkTextIndexBackChars(textPtr, indexPtr, 1, &rounded, COUNT_INDICES);
-       indexPtr = &rounded;
-    }
-
-    if (pickPlace == TK_TEXT_NOPIXELADJUST) {
-       if (textPtr->topIndex.linePtr == indexPtr->linePtr
-               && textPtr->topIndex.byteIndex == indexPtr->byteIndex) {
-           pickPlace = dInfoPtr->topPixelOffset;
-       } else {
-           pickPlace = 0;
-       }
-    }
-
-    if (pickPlace != TK_TEXT_PICKPLACE) {
-       /*
-        * The specified position must go at the top of the screen. Just leave
-        * all the DLine's alone: we may be able to reuse some of the
-        * information that's currently on the screen without redisplaying it
-        * all.
-        */
-
-       textPtr->topIndex = *indexPtr;
-        if (!IsStartOfNotMergedLine(textPtr, indexPtr)) {
-            TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
-        }
-       dInfoPtr->newTopPixelOffset = pickPlace;
-       goto scheduleUpdate;
-    }
-
-    /*
-     * We have to pick where to display the index. First, bring the display
-     * information up to date and see if the index will be completely visible
-     * in the current screen configuration. If so then there's nothing to do.
-     */
-
-    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
-       UpdateDisplayInfo(textPtr);
-    }
-    dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
-    if (dlPtr != NULL) {
-       if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) {
-           /*
-            * Part of the line hangs off the bottom of the screen; pretend
-            * the whole line is off-screen.
-            */
-
-           dlPtr = NULL;
-        } else {
-            if (TkTextIndexCmp(&dlPtr->index, indexPtr) <= 0) {
-                if (dInfoPtr->dLinePtr == dlPtr && dInfoPtr->topPixelOffset != 0) {
-                    /*
-                     * It is on the top line, but that line is hanging off the top
-                     * of the screen. Change the top overlap to zero and update.
-                     */
-
-                    dInfoPtr->newTopPixelOffset = 0;
-                    goto scheduleUpdate;
-                   }
-                return;
-            }
-        }
-    }
-
-    /*
-     * The desired line isn't already on-screen. Figure out what it means to
-     * be "close" to the top or bottom of the screen. Close means within 1/3
-     * of the screen height or within three lines, whichever is greater.
-     *
-     * If the line is not close, place it in the center of the window.
-     */
-
-    tmpIndex = *indexPtr;
-    TkTextFindDisplayLineEnd(textPtr, &tmpIndex, 0, NULL);
-    lineHeight = CalculateDisplayLineHeight(textPtr, &tmpIndex, NULL, NULL);
-
-    /*
-     * It would be better if 'bottomY' were calculated using the actual height
-     * of the given line, not 'textPtr->charHeight'.
-     */
-
-    bottomY = (dInfoPtr->y + dInfoPtr->maxY + lineHeight)/2;
-    close = (dInfoPtr->maxY - dInfoPtr->y)/3;
-    if (close < 3*textPtr->charHeight) {
-       close = 3*textPtr->charHeight;
-    }
-    if (dlPtr != NULL) {
-       int overlap;
-
-       /*
-        * The desired line is above the top of screen. If it is "close" to
-        * the top of the window then make it the top line on the screen.
-        * MeasureUp counts from the bottom of the given index upwards, so we
-        * add an extra half line to be sure we count far enough.
-        */
-
-       MeasureUp(textPtr, &textPtr->topIndex, close + textPtr->charHeight/2,
-               &tmpIndex, &overlap);
-       if (TkTextIndexCmp(&tmpIndex, indexPtr) <= 0) {
-           textPtr->topIndex = *indexPtr;
-           TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
-           dInfoPtr->newTopPixelOffset = 0;
-           goto scheduleUpdate;
-       }
-    } else {
-       int overlap;
-
-       /*
-        * The desired line is below the bottom of the screen. If it is
-        * "close" to the bottom of the screen then position it at the bottom
-        * of the screen.
-        */
-
-       MeasureUp(textPtr, indexPtr, close + lineHeight
-               - textPtr->charHeight/2, &tmpIndex, &overlap);
-       if (FindDLine(textPtr, dInfoPtr->dLinePtr, &tmpIndex) != NULL) {
-           bottomY = dInfoPtr->maxY - dInfoPtr->y;
-       }
-    }
-
-    /*
-     * Our job now is to arrange the display so that indexPtr appears as low
-     * on the screen as possible but with its bottom no lower than bottomY.
-     * BottomY is the bottom of the window if the desired line is just below
-     * the current screen, otherwise it is a half-line lower than the center
-     * of the window.
-     */
-
-    MeasureUp(textPtr, indexPtr, bottomY, &textPtr->topIndex,
-           &dInfoPtr->newTopPixelOffset);
-
-  scheduleUpdate:
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-    dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED;
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * TkTextMeasureDown --
- *
- *     Given one index, find the index of the first character on the highest
- *     display line that would be displayed no more than "distance" pixels
- *     below the top of the given index.
- *
- * Results:
- *     The srcPtr is manipulated in place to reflect the new position. We
- *     return the number of pixels by which 'distance' overlaps the srcPtr.
- *
- * Side effects:
- *     None.
- *
- *--------------------------------------------------------------
- */
-
-int
-TkTextMeasureDown(
-    TkText *textPtr,           /* Text widget in which to measure. */
-    TkTextIndex *srcPtr,       /* Index of character from which to start
-                                * measuring. */
-    int distance)              /* Vertical distance in pixels measured from
-                                * the top pixel in srcPtr's logical line. */
-{
-    TkTextLine *lastLinePtr;
-    DLine *dlPtr;
-    TkTextIndex loop;
-
-    lastLinePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, textPtr,
-           TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr));
-
-    do {
-       dlPtr = LayoutDLine(textPtr, srcPtr);
-       dlPtr->nextPtr = NULL;
-
-       if (distance < dlPtr->height) {
-           FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP);
-           break;
-       }
-       distance -= dlPtr->height;
-       TkTextIndexForwBytes(textPtr, srcPtr, dlPtr->byteCount, &loop);
-       FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP);
-       if (loop.linePtr == lastLinePtr) {
-           break;
-       }
-       *srcPtr = loop;
-    } while (distance > 0);
-
-    return distance;
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * MeasureUp --
- *
- *     Given one index, find the index of the first character on the highest
- *     display line that would be displayed no more than "distance" pixels
- *     above the given index.
- *
- *     If this function is called with distance=0, it simply finds the first
- *     index on the same display line as srcPtr. However, there is a another
- *     function TkTextFindDisplayLineEnd designed just for that task which is
- *     probably better to use.
- *
- * Results:
- *     *dstPtr is filled in with the index of the first character on a
- *     display line. The display line is found by measuring up "distance"
- *     pixels above the pixel just below an imaginary display line that
- *     contains srcPtr. If the display line that covers this coordinate
- *     actually extends above the coordinate, then return any excess pixels
- *     in *overlap, if that is non-NULL.
- *
- * Side effects:
- *     None.
- *
- *--------------------------------------------------------------
- */
-
-static void
-MeasureUp(
-    TkText *textPtr,           /* Text widget in which to measure. */
-    const TkTextIndex *srcPtr, /* Index of character from which to start
-                                * measuring. */
-    int distance,              /* Vertical distance in pixels measured from
-                                * the pixel just below the lowest one in
-                                * srcPtr's line. */
-    TkTextIndex *dstPtr,       /* Index to fill in with result. */
-    int *overlap)              /* Used to store how much of the final index
-                                * returned was not covered by 'distance'. */
-{
-    int lineNum;               /* Number of current line. */
-    int bytesToCount;          /* Maximum number of bytes to measure in
-                                * current line. */
-    TkTextIndex index;
-    DLine *dlPtr, *lowestPtr;
-
-    bytesToCount = srcPtr->byteIndex + 1;
-    index.tree = srcPtr->tree;
-    for (lineNum = TkBTreeLinesTo(textPtr, srcPtr->linePtr); lineNum >= 0;
-           lineNum--) {
-       /*
-        * Layout an entire text line (potentially > 1 display line).
-        *
-        * For the first line, which contains srcPtr, only layout the part up
-        * through srcPtr (bytesToCount is non-infinite to accomplish this).
-        * Make a list of all the display lines in backwards order (the lowest
-        * DLine on the screen is first in the list).
-        */
-
-       index.linePtr = TkBTreeFindLine(srcPtr->tree, textPtr, lineNum);
-       index.byteIndex = 0;
-        TkTextFindDisplayLineEnd(textPtr, &index, 0, NULL);
-        lineNum = TkBTreeLinesTo(textPtr, index.linePtr);
-       lowestPtr = NULL;
-       do {
-           dlPtr = LayoutDLine(textPtr, &index);
-           dlPtr->nextPtr = lowestPtr;
-           lowestPtr = dlPtr;
-           TkTextIndexForwBytes(textPtr, &index, dlPtr->byteCount, &index);
-           bytesToCount -= dlPtr->byteCount;
-       } while (bytesToCount>0 && index.linePtr==dlPtr->index.linePtr);
-
-       /*
-        * Scan through the display lines to see if we've covered enough
-        * vertical distance. If so, save the starting index for the line at
-        * the desired location. If distance was zero to start with then we
-        * simply get the first index on the same display line as the original
-        * index.
-        */
-
-       for (dlPtr = lowestPtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) {
-           distance -= dlPtr->height;
-           if (distance <= 0) {
-                *dstPtr = dlPtr->index;
-
-                /*
-                 * dstPtr is the start of a display line that is or is not
-                 * the start of a logical line. If it is the start of a
-                 * logical line, we must check whether this line is merged
-                 * with the previous logical line, and if so we must adjust
-                 * dstPtr to the start of the display line since a display
-                 * line start needs to be returned.
-                 */
-                if (!IsStartOfNotMergedLine(textPtr, dstPtr)) {
-                    TkTextFindDisplayLineEnd(textPtr, dstPtr, 0, NULL);
-                }
-
-                if (overlap != NULL) {
-                   *overlap = -distance;
-               }
-               break;
-           }
-       }
-
-       /*
-        * Discard the display lines, then either return or prepare for the
-        * next display line to lay out.
-        */
-
-       FreeDLines(textPtr, lowestPtr, NULL, DLINE_FREE);
-       if (distance <= 0) {
-           return;
-       }
-       bytesToCount = INT_MAX;         /* Consider all chars. in next line. */
-    }
-
-    /*
-     * Ran off the beginning of the text. Return the first character in the
-     * text.
-     */
-
-    TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, 0, 0, dstPtr);
-    if (overlap != NULL) {
-       *overlap = 0;
-    }
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * TkTextSeeCmd --
- *
- *     This function is invoked to process the "see" option for the widget
- *     command for text widgets. See the user documentation for details on
- *     what it does.
- *
- * Results:
- *     A standard Tcl result.
- *
- * Side effects:
- *     See the user documentation.
- *
- *--------------------------------------------------------------
- */
-
-int
-TkTextSeeCmd(
-    TkText *textPtr,           /* Information about text widget. */
-    Tcl_Interp *interp,                /* Current interpreter. */
-    int objc,                  /* Number of arguments. */
-    Tcl_Obj *const objv[])     /* Argument objects. Someone else has already
-                                * parsed this command enough to know that
-                                * objv[1] is "see". */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    TkTextIndex index;
-    int x, y, width, height, lineWidth, byteCount, oneThird, delta;
-    DLine *dlPtr;
-    TkTextDispChunk *chunkPtr;
-
-    if (objc != 3) {
-       Tcl_WrongNumArgs(interp, 2, objv, "index");
-       return TCL_ERROR;
-    }
-    if (TkTextGetObjIndex(interp, textPtr, objv[2], &index) != TCL_OK) {
-       return TCL_ERROR;
-    }
-
-    /*
-     * If the specified position is the extra line at the end of the text,
-     * round it back to the last real line.
-     */
-
-    if (TkBTreeLinesTo(textPtr, index.linePtr)
-           == TkBTreeNumLines(index.tree, textPtr)) {
-       TkTextIndexBackChars(textPtr, &index, 1, &index, COUNT_INDICES);
-    }
-
-    /*
-     * First get the desired position into the vertical range of the window.
-     */
-
-    TkTextSetYView(textPtr, &index, TK_TEXT_PICKPLACE);
-
-    /*
-     * Now make sure that the character is in view horizontally.
-     */
-
-    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
-       UpdateDisplayInfo(textPtr);
-    }
-    lineWidth = dInfoPtr->maxX - dInfoPtr->x;
-    if (dInfoPtr->maxLength < lineWidth) {
-       return TCL_OK;
-    }
-
-    /*
-     * Find the display line containing the desired index. dlPtr may be NULL
-     * if the widget is not mapped. [Bug #641778]
-     */
-
-    dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &index);
-    if (dlPtr == NULL) {
-       return TCL_OK;
-    }
-
-    /*
-     * Find the chunk within the display line that contains the desired
-     * index. The chunks making the display line are skipped up to but not
-     * including the one crossing index. Skipping is done based on a
-     * byteCount offset possibly spanning several logical lines in case
-     * they are elided.
-     */
-
-    byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, &index);
-    for (chunkPtr = dlPtr->chunkPtr; chunkPtr != NULL ;
-           chunkPtr = chunkPtr->nextPtr) {
-       if (byteCount < chunkPtr->numBytes) {
-           break;
-       }
-       byteCount -= chunkPtr->numBytes;
-    }
-
-    /*
-     * Call a chunk-specific function to find the horizontal range of the
-     * character within the chunk. chunkPtr is NULL if trying to see in elided
-     * region.
-     */
-
-    if (chunkPtr != NULL) {
-        chunkPtr->bboxProc(textPtr, chunkPtr, byteCount,
-                dlPtr->y + dlPtr->spaceAbove,
-                dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
-                dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width,
-                &height);
-        delta = x - dInfoPtr->curXPixelOffset;
-        oneThird = lineWidth/3;
-        if (delta < 0) {
-            if (delta < -oneThird) {
-                dInfoPtr->newXPixelOffset = x - lineWidth/2;
-            } else {
-                dInfoPtr->newXPixelOffset += delta;
-            }
-        } else {
-            delta -= lineWidth - width;
-            if (delta <= 0) {
-                return TCL_OK;
-            }
-            if (delta > oneThird) {
-                dInfoPtr->newXPixelOffset = x - lineWidth/2;
-            } else {
-                dInfoPtr->newXPixelOffset += delta;
-            }
-        }
-    }
-    dInfoPtr->flags |= DINFO_OUT_OF_DATE;
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       dInfoPtr->flags |= REDRAW_PENDING;
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-    return TCL_OK;
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * TkTextXviewCmd --
- *
- *     This function is invoked to process the "xview" option for the widget
- *     command for text widgets. See the user documentation for details on
- *     what it does.
- *
- * Results:
- *     A standard Tcl result.
- *
- * Side effects:
- *     See the user documentation.
- *
- *--------------------------------------------------------------
- */
-
-int
-TkTextXviewCmd(
-    TkText *textPtr,           /* Information about text widget. */
-    Tcl_Interp *interp,                /* Current interpreter. */
-    int objc,                  /* Number of arguments. */
-    Tcl_Obj *const objv[])     /* Argument objects. Someone else has already
-                                * parsed this command enough to know that
-                                * objv[1] is "xview". */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    int type, count;
-    double fraction;
-
-    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
-       UpdateDisplayInfo(textPtr);
-    }
-
-    if (objc == 2) {
-       GetXView(interp, textPtr, 0);
-       return TCL_OK;
-    }
-
-    type = TextGetScrollInfoObj(interp, textPtr, objc, objv,
-           &fraction, &count);
-    switch (type) {
-    case TKTEXT_SCROLL_ERROR:
-       return TCL_ERROR;
-    case TKTEXT_SCROLL_MOVETO:
-       if (fraction > 1.0) {
-           fraction = 1.0;
-       }
-       if (fraction < 0) {
-           fraction = 0;
-       }
-       dInfoPtr->newXPixelOffset = (int)
-               (fraction * dInfoPtr->maxLength + 0.5);
-       break;
-    case TKTEXT_SCROLL_PAGES: {
-       int pixelsPerPage;
-
-       pixelsPerPage = (dInfoPtr->maxX-dInfoPtr->x) - 2*textPtr->charWidth;
-       if (pixelsPerPage < 1) {
-           pixelsPerPage = 1;
-       }
-       dInfoPtr->newXPixelOffset += pixelsPerPage * count;
-       break;
-    }
-    case TKTEXT_SCROLL_UNITS:
-       dInfoPtr->newXPixelOffset += count * textPtr->charWidth;
-       break;
-    case TKTEXT_SCROLL_PIXELS:
-       dInfoPtr->newXPixelOffset += count;
-       break;
-    }
-
-    dInfoPtr->flags |= DINFO_OUT_OF_DATE;
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       dInfoPtr->flags |= REDRAW_PENDING;
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-    return TCL_OK;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * YScrollByPixels --
- *
- *     This function is called to scroll a text widget up or down by a given
- *     number of pixels.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The view in textPtr's window changes to reflect the value of "offset".
- *
- *----------------------------------------------------------------------
- */
-
-static void
-YScrollByPixels(
-    TkText *textPtr,           /* Widget to scroll. */
-    int offset)                        /* Amount by which to scroll, in pixels.
-                                * Positive means that information later in
-                                * text becomes visible, negative means that
-                                * information earlier in the text becomes
-                                * visible. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-
-    if (offset < 0) {
-       /*
-        * Now we want to measure up this number of pixels from the top of the
-        * screen. But the top line may not be totally visible. Note that
-        * 'count' is negative here.
-        */
-
-       offset -= CalculateDisplayLineHeight(textPtr,
-               &textPtr->topIndex, NULL, NULL) - dInfoPtr->topPixelOffset;
-       MeasureUp(textPtr, &textPtr->topIndex, -offset,
-               &textPtr->topIndex, &dInfoPtr->newTopPixelOffset);
-    } else if (offset > 0) {
-       DLine *dlPtr;
-       TkTextLine *lastLinePtr;
-       TkTextIndex newIdx;
-
-       /*
-        * Scrolling down by pixels. Layout lines starting at the top index
-        * and count through the desired vertical distance.
-        */
-
-       lastLinePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, textPtr,
-               TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr));
-       offset += dInfoPtr->topPixelOffset;
-       dInfoPtr->newTopPixelOffset = 0;
-       while (offset > 0) {
-           dlPtr = LayoutDLine(textPtr, &textPtr->topIndex);
-           dlPtr->nextPtr = NULL;
-           TkTextIndexForwBytes(textPtr, &textPtr->topIndex,
-                   dlPtr->byteCount, &newIdx);
-           if (offset <= dlPtr->height) {
-               /*
-                * Adjust the top overlap accordingly.
-                */
-
-               dInfoPtr->newTopPixelOffset = offset;
-           }
-           offset -= dlPtr->height;
-           FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP);
-           if (newIdx.linePtr == lastLinePtr || offset <= 0) {
-               break;
-           }
-           textPtr->topIndex = newIdx;
-       }
-    } else {
-       /*
-        * offset = 0, so no scrolling required.
-        */
-
-       return;
-    }
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-    dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * YScrollByLines --
- *
- *     This function is called to scroll a text widget up or down by a given
- *     number of lines.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The view in textPtr's window changes to reflect the value of "offset".
- *
- *----------------------------------------------------------------------
- */
-
-static void
-YScrollByLines(
-    TkText *textPtr,           /* Widget to scroll. */
-    int offset)                        /* Amount by which to scroll, in display
-                                * lines. Positive means that information
-                                * later in text becomes visible, negative
-                                * means that information earlier in the text
-                                * becomes visible. */
-{
-    int i, bytesToCount, lineNum;
-    TkTextIndex newIdx, index;
-    TkTextLine *lastLinePtr;
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    DLine *dlPtr, *lowestPtr;
-
-    if (offset < 0) {
-       /*
-        * Must scroll up (to show earlier information in the text). The code
-        * below is similar to that in MeasureUp, except that it counts lines
-        * instead of pixels.
-        */
-
-       bytesToCount = textPtr->topIndex.byteIndex + 1;
-       index.tree = textPtr->sharedTextPtr->tree;
-       offset--;               /* Skip line containing topIndex. */
-       for (lineNum = TkBTreeLinesTo(textPtr, textPtr->topIndex.linePtr);
-               lineNum >= 0; lineNum--) {
-           index.linePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree,
-                   textPtr, lineNum);
-           index.byteIndex = 0;
-           lowestPtr = NULL;
-           do {
-               dlPtr = LayoutDLine(textPtr, &index);
-               dlPtr->nextPtr = lowestPtr;
-               lowestPtr = dlPtr;
-               TkTextIndexForwBytes(textPtr, &index, dlPtr->byteCount,&index);
-               bytesToCount -= dlPtr->byteCount;
-           } while ((bytesToCount > 0)
-                   && (index.linePtr == dlPtr->index.linePtr));
-
-           for (dlPtr = lowestPtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) {
-               offset++;
-               if (offset == 0) {
-                   textPtr->topIndex = dlPtr->index;
-
-                    /*
-                     * topIndex is the start of a logical line. However, if
-                     * the eol of the previous logical line is elided, then
-                     * topIndex may be elsewhere than the first character of
-                     * a display line, which is unwanted. Adjust to the start
-                     * of the display line, if needed.
-                     * topIndex is the start of a display line that is or is
-                     * not the start of a logical line. If it is the start of
-                     * a logical line, we must check whether this line is
-                     * merged with the previous logical line, and if so we
-                     * must adjust topIndex to the start of the display line.
-                     */
-                    if (!IsStartOfNotMergedLine(textPtr, &textPtr->topIndex)) {
-                        TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex,
-                                0, NULL);
-                    }
-
-                    break;
-               }
-           }
-
-           /*
-            * Discard the display lines, then either return or prepare for
-            * the next display line to lay out.
-            */
-
-           FreeDLines(textPtr, lowestPtr, NULL, DLINE_FREE);
-           if (offset >= 0) {
-               goto scheduleUpdate;
-           }
-           bytesToCount = INT_MAX;
-       }
-
-       /*
-        * Ran off the beginning of the text. Return the first character in
-        * the text, and make sure we haven't left anything overlapping the
-        * top window border.
-        */
-
-       TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr, 0, 0,
-               &textPtr->topIndex);
-       dInfoPtr->newTopPixelOffset = 0;
-    } else {
-       /*
-        * Scrolling down, to show later information in the text. Just count
-        * lines from the current top of the window.
-        */
-
-       lastLinePtr = TkBTreeFindLine(textPtr->sharedTextPtr->tree, textPtr,
-               TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr));
-       for (i = 0; i < offset; i++) {
-           dlPtr = LayoutDLine(textPtr, &textPtr->topIndex);
-           if (dlPtr->length == 0 && dlPtr->height == 0) {
-               offset++;
-           }
-           dlPtr->nextPtr = NULL;
-           TkTextIndexForwBytes(textPtr, &textPtr->topIndex,
-                   dlPtr->byteCount, &newIdx);
-           FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE);
-           if (newIdx.linePtr == lastLinePtr) {
-               break;
-           }
-           textPtr->topIndex = newIdx;
-       }
-    }
-
-  scheduleUpdate:
-    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-       Tcl_DoWhenIdle(DisplayText, textPtr);
-    }
-    dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED;
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * TkTextYviewCmd --
- *
- *     This function is invoked to process the "yview" option for the widget
- *     command for text widgets. See the user documentation for details on
- *     what it does.
- *
- * Results:
- *     A standard Tcl result.
- *
- * Side effects:
- *     See the user documentation.
- *
- *--------------------------------------------------------------
- */
-
-int
-TkTextYviewCmd(
-    TkText *textPtr,           /* Information about text widget. */
-    Tcl_Interp *interp,                /* Current interpreter. */
-    int objc,                  /* Number of arguments. */
-    Tcl_Obj *const objv[])     /* Argument objects. Someone else has already
-                                * parsed this command enough to know that
-                                * objv[1] is "yview". */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    int pickPlace, type;
-    int pixels, count;
-    int switchLength;
-    double fraction;
-    TkTextIndex index;
-
-    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
-       UpdateDisplayInfo(textPtr);
-    }
-
-    if (objc == 2) {
-       GetYView(interp, textPtr, 0);
-       return TCL_OK;
-    }
-
-    /*
-     * Next, handle the old syntax: "pathName yview ?-pickplace? where"
-     */
-
-    pickPlace = 0;
-    if (Tcl_GetString(objv[2])[0] == '-') {
-       register const char *switchStr =
-               Tcl_GetStringFromObj(objv[2], &switchLength);
-
-       if ((switchLength >= 2) && (strncmp(switchStr, "-pickplace",
-               (unsigned) switchLength) == 0)) {
-           pickPlace = 1;
-           if (objc != 4) {
-               Tcl_WrongNumArgs(interp, 3, objv, "lineNum|index");
-               return TCL_ERROR;
-           }
-       }
-    }
-    if ((objc == 3) || pickPlace) {
-       int lineNum;
-
-       if (Tcl_GetIntFromObj(interp, objv[2+pickPlace], &lineNum) == TCL_OK) {
-           TkTextMakeByteIndex(textPtr->sharedTextPtr->tree, textPtr,
-                   lineNum, 0, &index);
-           TkTextSetYView(textPtr, &index, 0);
-           return TCL_OK;
-       }
-
-       /*
-        * The argument must be a regular text index.
-        */
-
-       Tcl_ResetResult(interp);
-       if (TkTextGetObjIndex(interp, textPtr, objv[2+pickPlace],
-               &index) != TCL_OK) {
-           return TCL_ERROR;
-       }
-       TkTextSetYView(textPtr, &index, (pickPlace ? TK_TEXT_PICKPLACE : 0));
-       return TCL_OK;
-    }
-
-    /*
-     * New syntax: dispatch based on objv[2].
-     */
-
-    type = TextGetScrollInfoObj(interp, textPtr, objc,objv, &fraction, &count);
-    switch (type) {
-    case TKTEXT_SCROLL_ERROR:
-       return TCL_ERROR;
-    case TKTEXT_SCROLL_MOVETO: {
-       int numPixels = TkBTreeNumPixels(textPtr->sharedTextPtr->tree,
-               textPtr);
-       int topMostPixel;
-
-       if (numPixels == 0) {
-           /*
-            * If the window is totally empty no scrolling is needed, and the
-            * TkTextMakePixelIndex call below will fail.
-            */
-
-           break;
-       }
-       if (fraction > 1.0) {
-           fraction = 1.0;
-       }
-       if (fraction < 0) {
-           fraction = 0;
-       }
-
-       /*
-        * Calculate the pixel count for the new topmost pixel in the topmost
-        * line of the window. Note that the interpretation of 'fraction' is
-        * that it counts from 0 (top pixel in buffer) to 1.0 (one pixel past
-        * the last pixel in buffer).
-        */
-
-       topMostPixel = (int) (0.5 + fraction * numPixels);
-       if (topMostPixel >= numPixels) {
-           topMostPixel = numPixels -1;
-       }
-
-       /*
-        * This function returns the number of pixels by which the given line
-        * should overlap the top of the visible screen.
-        *
-        * This is then used to provide smooth scrolling.
-        */
-
-       pixels = TkTextMakePixelIndex(textPtr, topMostPixel, &index);
-       TkTextSetYView(textPtr, &index, pixels);
-       break;
-    }
-    case TKTEXT_SCROLL_PAGES: {
-       /*
-        * Scroll up or down by screenfuls. Actually, use the window height
-        * minus two lines, so that there's some overlap between adjacent
-        * pages.
-        */
-
-       int height = dInfoPtr->maxY - dInfoPtr->y;
-
-       if (textPtr->charHeight * 4 >= height) {
-           /*
-            * A single line is more than a quarter of the display. We choose
-            * to scroll by 3/4 of the height instead.
-            */
-
-           pixels = 3*height/4;
-           if (pixels < textPtr->charHeight) {
-               /*
-                * But, if 3/4 of the height is actually less than a single
-                * typical character height, then scroll by the minimum of the
-                * linespace or the total height.
-                */
-
-               if (textPtr->charHeight < height) {
-                   pixels = textPtr->charHeight;
-               } else {
-                   pixels = height;
-               }
-           }
-           pixels *= count;
-       } else {
-           pixels = (height - 2*textPtr->charHeight)*count;
-       }
-       YScrollByPixels(textPtr, pixels);
-       break;
-    }
-    case TKTEXT_SCROLL_PIXELS:
-       YScrollByPixels(textPtr, count);
-       break;
-    case TKTEXT_SCROLL_UNITS:
-       YScrollByLines(textPtr, count);
-       break;
-    }
-    return TCL_OK;
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * TkTextScanCmd --
- *
- *     This function is invoked to process the "scan" option for the widget
- *     command for text widgets. See the user documentation for details on
- *     what it does.
- *
- * Results:
- *     A standard Tcl result.
- *
- * Side effects:
- *     See the user documentation.
- *
- *--------------------------------------------------------------
- */
-
-int
-TkTextScanCmd(
-    register TkText *textPtr,  /* Information about text widget. */
-    Tcl_Interp *interp,                /* Current interpreter. */
-    int objc,                  /* Number of arguments. */
-    Tcl_Obj *const objv[])     /* Argument objects. Someone else has already
-                                * parsed this command enough to know that
-                                * objv[1] is "scan". */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    TkTextIndex index;
-    int c, x, y, totalScroll, gain=10;
-    size_t length;
-
-    if ((objc != 5) && (objc != 6)) {
-       Tcl_WrongNumArgs(interp, 2, objv, "mark x y");
-       Tcl_AppendResult(interp, " or \"", Tcl_GetString(objv[0]),
-               " scan dragto x y ?gain?\"", NULL);
-       /*
-        * Ought to be:
-        * Tcl_WrongNumArgs(interp, 2, objc, "dragto x y ?gain?");
-        */
-       return TCL_ERROR;
-    }
-    if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK) {
-       return TCL_ERROR;
-    }
-    if ((objc == 6) && (Tcl_GetIntFromObj(interp, objv[5], &gain) != TCL_OK)) {
-       return TCL_ERROR;
-    }
-    c = Tcl_GetString(objv[2])[0];
-    length = strlen(Tcl_GetString(objv[2]));
-    if (c=='d' && strncmp(Tcl_GetString(objv[2]), "dragto", length)==0) {
-       int newX, maxX;
-
-       /*
-        * Amplify the difference between the current position and the mark
-        * position to compute how much the view should shift, then update the
-        * mark position to correspond to the new view. If we run off the edge
-        * of the text, reset the mark point so that the current position
-        * continues to correspond to the edge of the window. This means that
-        * the picture will start dragging as soon as the mouse reverses
-        * direction (without this reset, might have to slide mouse a long
-        * ways back before the picture starts moving again).
-        */
-
-       newX = dInfoPtr->scanMarkXPixel + gain*(dInfoPtr->scanMarkX - x);
-       maxX = 1 + dInfoPtr->maxLength - (dInfoPtr->maxX - dInfoPtr->x);
-       if (newX < 0) {
-           newX = 0;
-           dInfoPtr->scanMarkXPixel = 0;
-           dInfoPtr->scanMarkX = x;
-       } else if (newX > maxX) {
-           newX = maxX;
-           dInfoPtr->scanMarkXPixel = maxX;
-           dInfoPtr->scanMarkX = x;
-       }
-       dInfoPtr->newXPixelOffset = newX;
-
-       totalScroll = gain*(dInfoPtr->scanMarkY - y);
-       if (totalScroll != dInfoPtr->scanTotalYScroll) {
-           index = textPtr->topIndex;
-           YScrollByPixels(textPtr, totalScroll-dInfoPtr->scanTotalYScroll);
-           dInfoPtr->scanTotalYScroll = totalScroll;
-           if ((index.linePtr == textPtr->topIndex.linePtr) &&
-                   (index.byteIndex == textPtr->topIndex.byteIndex)) {
-               dInfoPtr->scanTotalYScroll = 0;
-               dInfoPtr->scanMarkY = y;
-           }
-       }
-       dInfoPtr->flags |= DINFO_OUT_OF_DATE;
-       if (!(dInfoPtr->flags & REDRAW_PENDING)) {
-           dInfoPtr->flags |= REDRAW_PENDING;
-           Tcl_DoWhenIdle(DisplayText, textPtr);
-       }
-    } else if (c=='m' && strncmp(Tcl_GetString(objv[2]), "mark", length)==0) {
-       dInfoPtr->scanMarkXPixel = dInfoPtr->newXPixelOffset;
-       dInfoPtr->scanMarkX = x;
-       dInfoPtr->scanTotalYScroll = 0;
-       dInfoPtr->scanMarkY = y;
-    } else {
-       Tcl_SetObjResult(interp, Tcl_ObjPrintf(
-               "bad scan option \"%s\": must be mark or dragto",
-               Tcl_GetString(objv[2])));
-       Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "scan option",
-               Tcl_GetString(objv[2]), NULL);
-       return TCL_ERROR;
-    }
-    return TCL_OK;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * GetXView --
- *
- *     This function computes the fractions that indicate what's visible in a
- *     text window and, optionally, evaluates a Tcl script to report them to
- *     the text's associated scrollbar.
- *
- * Results:
- *     If report is zero, then the interp's result is filled in with two real
- *     numbers separated by a space, giving the position of the left and
- *     right edges of the window as fractions from 0 to 1, where 0 means the
- *     left edge of the text and 1 means the right edge. If report is
- *     non-zero, then the interp's result isn't modified directly, but
- *     instead a script is evaluated in interp to report the new horizontal
- *     scroll position to the scrollbar (if the scroll position hasn't
- *     changed then no script is invoked).
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-GetXView(
-    Tcl_Interp *interp,                /* If "report" is FALSE, string describing
-                                * visible range gets stored in the interp's
-                                * result. */
-    TkText *textPtr,           /* Information about text widget. */
-    int report)                        /* Non-zero means report info to scrollbar if
-                                * it has changed. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    double first, last;
-    int code;
-    Tcl_Obj *listObj;
-
-    if (dInfoPtr->maxLength > 0) {
-       first = ((double) dInfoPtr->curXPixelOffset)
-               / dInfoPtr->maxLength;
-       last = ((double) (dInfoPtr->curXPixelOffset + dInfoPtr->maxX
-               - dInfoPtr->x))/dInfoPtr->maxLength;
-       if (last > 1.0) {
-           last = 1.0;
-       }
-    } else {
-       first = 0;
-       last = 1.0;
-    }
-    if (!report) {
-       listObj = Tcl_NewListObj(0, NULL);
-       Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(first));
-       Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(last));
-       Tcl_SetObjResult(interp, listObj);
-       return;
-    }
-    if (FP_EQUAL_SCALE(first, dInfoPtr->xScrollFirst, dInfoPtr->maxLength) &&
-           FP_EQUAL_SCALE(last, dInfoPtr->xScrollLast, dInfoPtr->maxLength)) {
-       return;
-    }
-    dInfoPtr->xScrollFirst = first;
-    dInfoPtr->xScrollLast = last;
-    if (textPtr->xScrollCmd != NULL) {
-       char buf1[TCL_DOUBLE_SPACE+1];
-       char buf2[TCL_DOUBLE_SPACE+1];
-       Tcl_DString buf;
-
-       buf1[0] = ' ';
-       buf2[0] = ' ';
-       Tcl_PrintDouble(NULL, first, buf1+1);
-       Tcl_PrintDouble(NULL, last, buf2+1);
-       Tcl_DStringInit(&buf);
-       Tcl_DStringAppend(&buf, textPtr->xScrollCmd, -1);
-       Tcl_DStringAppend(&buf, buf1, -1);
-       Tcl_DStringAppend(&buf, buf2, -1);
-       code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0);
-       Tcl_DStringFree(&buf);
-       if (code != TCL_OK) {
-           Tcl_AddErrorInfo(interp,
-                   "\n    (horizontal scrolling command executed by text)");
-           Tcl_BackgroundException(interp, code);
-       }
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * GetYPixelCount --
- *
- *     How many pixels are there between the absolute top of the widget and
- *     the top of the given DLine.
- *
- *     While this function will work for any valid DLine, it is only ever
- *     called when dlPtr is the first display line in the widget (by
- *     'GetYView'). This means that usually this function is a very quick
- *     calculation, since it can use the pre-calculated linked-list of DLines
- *     for height information.
- *
- *     The only situation where this breaks down is if dlPtr's logical line
- *     wraps enough times to fill the text widget's current view - in this
- *     case we won't have enough dlPtrs in the linked list to be able to
- *     subtract off what we want.
- *
- * Results:
- *     The number of pixels.
- *
- *     This value has a valid range between '0' (the very top of the widget)
- *     and the number of pixels in the total widget minus the pixel-height of
- *     the last line.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-GetYPixelCount(
-    TkText *textPtr,           /* Information about text widget. */
-    DLine *dlPtr)              /* Information about the layout of a given
-                                * index. */
-{
-    TkTextLine *linePtr = dlPtr->index.linePtr;
-    int count;
-
-    /*
-     * Get the pixel count to the top of dlPtr's logical line. The rest of the
-     * function is then concerned with updating 'count' for any difference
-     * between the top of the logical line and the display line.
-     */
-
-    count = TkBTreePixelsTo(textPtr, linePtr);
-
-    /*
-     * For the common case where this dlPtr is also the start of the logical
-     * line, we can return right away.
-     */
-
-    if (IsStartOfNotMergedLine(textPtr, &dlPtr->index)) {
-       return count;
-    }
-
-    /*
-     * Add on the logical line's height to reach one pixel beyond the bottom
-     * of the logical line. And then subtract off the heights of all the
-     * display lines from dlPtr to the end of its logical line.
-     *
-     * A different approach would be to lay things out from the start of the
-     * logical line until we reach dlPtr, but since none of those are
-     * pre-calculated, it'll usually take a lot longer. (But there are cases
-     * where it would be more efficient: say if we're on the second of 1000
-     * wrapped lines all from a single logical line - but that sort of
-     * optimization is left for the future).
-     */
-
-    count += TkBTreeLinePixelCount(textPtr, linePtr);
-
-    do {
-       count -= dlPtr->height;
-       if (dlPtr->nextPtr == NULL) {
-           /*
-            * We've run out of pre-calculated display lines, so we have to
-            * lay them out ourselves until the end of the logical line. Here
-            * is where we could be clever and ask: what's faster, to layout
-            * all lines from here to line-end, or all lines from the original
-            * dlPtr to the line-start? We just assume the former.
-            */
-
-           TkTextIndex index;
-           int notFirst = 0;
-
-           while (1) {
-               TkTextIndexForwBytes(textPtr, &dlPtr->index,
-                       dlPtr->byteCount, &index);
-               if (notFirst) {
-                   FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP);
-               }
-               if (index.linePtr != linePtr) {
-                   break;
-               }
-               dlPtr = LayoutDLine(textPtr, &index);
-
-               if (tkTextDebug) {
-                   char string[TK_POS_CHARS];
-
-                   /*
-                    * Debugging is enabled, so keep a log of all the lines
-                    * whose height was recalculated. The test suite uses this
-                    * information.
-                    */
-
-                   TkTextPrintIndex(textPtr, &index, string);
-                   LOG("tk_textHeightCalc", string);
-               }
-               count -= dlPtr->height;
-               notFirst = 1;
-           }
-           break;
-       }
-       dlPtr = dlPtr->nextPtr;
-    } while (dlPtr->index.linePtr == linePtr);
-
-    return count;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * GetYView --
- *
- *     This function computes the fractions that indicate what's visible in a
- *     text window and, optionally, evaluates a Tcl script to report them to
- *     the text's associated scrollbar.
- *
- * Results:
- *     If report is zero, then the interp's result is filled in with two real
- *     numbers separated by a space, giving the position of the top and
- *     bottom of the window as fractions from 0 to 1, where 0 means the
- *     beginning of the text and 1 means the end. If report is non-zero, then
- *     the interp's result isn't modified directly, but a script is evaluated
- *     in interp to report the new scroll position to the scrollbar (if the
- *     scroll position hasn't changed then no script is invoked).
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-GetYView(
-    Tcl_Interp *interp,                /* If "report" is FALSE, string describing
-                                * visible range gets stored in the interp's
-                                * result. */
-    TkText *textPtr,           /* Information about text widget. */
-    int report)                        /* Non-zero means report info to scrollbar if
-                                * it has changed. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    double first, last;
-    DLine *dlPtr;
-    int totalPixels, code, count;
-    Tcl_Obj *listObj;
-
-    dlPtr = dInfoPtr->dLinePtr;
-
-    if (dlPtr == NULL) {
-       return;
-    }
-
-    totalPixels = TkBTreeNumPixels(textPtr->sharedTextPtr->tree, textPtr);
-
-    if (totalPixels == 0) {
-       first = 0.0;
-       last = 1.0;
-    } else {
-       /*
-        * Get the pixel count for the first visible pixel of the first
-        * visible line. If the first visible line is only partially visible,
-        * then we use 'topPixelOffset' to get the difference.
-        */
-
-       count = GetYPixelCount(textPtr, dlPtr);
-       first = (count + dInfoPtr->topPixelOffset) / (double) totalPixels;
-
-       /*
-        * Add on the total number of visible pixels to get the count to one
-        * pixel _past_ the last visible pixel. This is how the 'yview'
-        * command is documented, and also explains why we are dividing by
-        * 'totalPixels' and not 'totalPixels-1'.
-        */
-
-       while (1) {
-           int extra;
-
-           count += dlPtr->height;
-           extra = dlPtr->y + dlPtr->height - dInfoPtr->maxY;
-           if (extra > 0) {
-               /*
-                * This much of the last line is not visible, so don't count
-                * these pixels. Since we've reached the bottom of the window,
-                * we break out of the loop.
-                */
-
-               count -= extra;
-               break;
-           }
-           if (dlPtr->nextPtr == NULL) {
-               break;
-           }
-           dlPtr = dlPtr->nextPtr;
-       }
-
-       if (count > totalPixels) {
-           /*
-            * It can be possible, if we do not update each line's pixelHeight
-            * cache when we lay out individual DLines that the count
-            * generated here is more up-to-date than that maintained by the
-            * BTree. In such a case, the best we can do here is to fix up
-            * 'count' and continue, which might result in small, temporary
-            * perturbations to the size of the scrollbar. This is basically
-            * harmless, but in a perfect world we would not have this
-            * problem.
-            *
-            * For debugging purposes, if anyone wishes to improve the text
-            * widget further, the following 'panic' can be activated. In
-            * principle it should be possible to ensure the BTree is always
-            * at least as up to date as the display, so in the future we
-            * might be able to leave the 'panic' in permanently when we
-            * believe we have resolved the cache synchronisation issue.
-            *
-            * However, to achieve that goal would, I think, require a fairly
-            * substantial refactorisation of the code in this file so that
-            * there is much more obvious and explicit coordination between
-            * calls to LayoutDLine and updating of each TkTextLine's
-            * pixelHeight. The complicated bit is that LayoutDLine deals with
-            * individual display lines, but pixelHeight is for a logical
-            * line.
-            */
-
-#if 0
-           Tcl_Panic("Counted more pixels (%d) than expected (%d) total "
-                   "pixels in text widget scroll bar calculation.", count,
-                   totalPixels);
-#endif
-           count = totalPixels;
-       }
-
-       last = ((double) count)/((double)totalPixels);
-    }
-
-    if (!report) {
-       listObj = Tcl_NewListObj(0,NULL);
-       Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(first));
-       Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(last));
-       Tcl_SetObjResult(interp, listObj);
-       return;
-    }
-
-    if (FP_EQUAL_SCALE(first, dInfoPtr->yScrollFirst, totalPixels) &&
-           FP_EQUAL_SCALE(last, dInfoPtr->yScrollLast, totalPixels)) {
-       return;
-    }
-
-    dInfoPtr->yScrollFirst = first;
-    dInfoPtr->yScrollLast = last;
-    if (textPtr->yScrollCmd != NULL) {
-       char buf1[TCL_DOUBLE_SPACE+1];
-       char buf2[TCL_DOUBLE_SPACE+1];
-       Tcl_DString buf;
-
-       buf1[0] = ' ';
-       buf2[0] = ' ';
-       Tcl_PrintDouble(NULL, first, buf1+1);
-       Tcl_PrintDouble(NULL, last, buf2+1);
-       Tcl_DStringInit(&buf);
-       Tcl_DStringAppend(&buf, textPtr->yScrollCmd, -1);
-       Tcl_DStringAppend(&buf, buf1, -1);
-       Tcl_DStringAppend(&buf, buf2, -1);
-       code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0);
-       Tcl_DStringFree(&buf);
-       if (code != TCL_OK) {
-           Tcl_AddErrorInfo(interp,
-                   "\n    (vertical scrolling command executed by text)");
-           Tcl_BackgroundException(interp, code);
-       }
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * AsyncUpdateYScrollbar --
- *
- *     This function is called to update the vertical scrollbar asychronously
- *     as the pixel height calculations progress for lines in the widget.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     See 'GetYView'. In particular the scrollbar position and size may be
- *     changed.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-AsyncUpdateYScrollbar(
-    ClientData clientData)     /* Information about widget. */
-{
-    register TkText *textPtr = clientData;
-
-    textPtr->dInfoPtr->scrollbarTimer = NULL;
-
-    if (!(textPtr->flags & DESTROYED)) {
-       GetYView(textPtr->interp, textPtr, 1);
-    }
-
-    if (--textPtr->refCount == 0) {
-       ckfree(textPtr);
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * FindDLine --
- *
- *     This function is called to find the DLine corresponding to a given
- *     text index.
- *
- * Results:
- *     The return value is a pointer to the first DLine found in the list
- *     headed by dlPtr that displays information at or after the specified
- *     position. If there is no such line in the list then NULL is returned.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static DLine *
-FindDLine(
-    TkText *textPtr,           /* Widget record for text widget. */
-    register DLine *dlPtr,     /* Pointer to first in list of DLines to
-                                * search. */
-    const TkTextIndex *indexPtr)/* Index of desired character. */
-{
-    DLine *dlPtrPrev;
-
-    if (dlPtr == NULL) {
-       return NULL;
-    }
-    if (TkBTreeLinesTo(NULL, indexPtr->linePtr)
-           < TkBTreeLinesTo(NULL, dlPtr->index.linePtr)) {
-       /*
-        * The first display line is already past the desired line.
-        */
-
-       return dlPtr;
-    }
-
-    /*
-     * The display line containing the desired index is such that the index
-     * of the first character of this display line is at or before the
-     * desired index, and the index of the first character of the next
-     * display line is after the desired index.
-     */
-
-    while (TkTextIndexCmp(&dlPtr->index,indexPtr) < 0) {
-        dlPtrPrev = dlPtr;
-        dlPtr = dlPtr->nextPtr;
-        if (dlPtr == NULL) {
-            TkTextIndex indexPtr2;
-            /*
-             * We're past the last display line, either because the desired
-             * index lies past the visible text, or because the desired index
-             * is on the last display line showing the last logical line.
-             */
-            indexPtr2 = dlPtrPrev->index;
-            TkTextIndexForwBytes(textPtr, &indexPtr2, dlPtrPrev->byteCount,
-                    &indexPtr2);
-            if (TkTextIndexCmp(&indexPtr2,indexPtr) > 0) {
-                dlPtr = dlPtrPrev;
-                break;
-            } else {
-                return NULL;
-            }
-        }
-        if (TkTextIndexCmp(&dlPtr->index,indexPtr) > 0) {
-            dlPtr = dlPtrPrev;
-            break;
-        }
-    }
-
-    return dlPtr;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * IsStartOfNotMergedLine --
- *
- *     This function checks whether the given index is the start of a
- *      logical line that is not merged with the previous logical line
- *      (due to elision of the eol of the previous line).
- *
- * Results:
- *     Returns whether the given index denotes the first index of a
-*       logical line not merged with its previous line.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-IsStartOfNotMergedLine(
-      TkText *textPtr,              /* Widget record for text widget. */
-      CONST TkTextIndex *indexPtr)  /* Index to check. */
-{
-    TkTextIndex indexPtr2;
-
-    if (indexPtr->byteIndex != 0) {
-        /*
-         * Not the start of a logical line.
-         */
-        return 0;
-    }
-
-    if (TkTextIndexBackBytes(textPtr, indexPtr, 1, &indexPtr2)) {
-        /*
-         * indexPtr is the first index of the text widget.
-         */
-        return 1;
-    }
-
-    if (!TkTextIsElided(textPtr, &indexPtr2, NULL)) {
-        /*
-         * The eol of the line just before indexPtr is elided.
-         */
-        return 1;
-    }
-
-    return 0;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextPixelIndex --
- *
- *     Given an (x,y) coordinate on the screen, find the location of the
- *     character closest to that location.
- *
- * Results:
- *     The index at *indexPtr is modified to refer to the character on the
- *     display that is closest to (x,y).
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextPixelIndex(
-    TkText *textPtr,           /* Widget record for text widget. */
-    int x, int y,              /* Pixel coordinates of point in widget's
-                                * window. */
-    TkTextIndex *indexPtr,     /* This index gets filled in with the index of
-                                * the character nearest to (x,y). */
-    int *nearest)              /* If non-NULL then gets set to 0 if (x,y) is
-                                * actually over the returned index, and 1 if
-                                * it is just nearby (e.g. if x,y is on the
-                                * border of the widget). */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    register DLine *dlPtr, *validDlPtr;
-    int nearby = 0;
-
-    /*
-     * Make sure that all of the layout information about what's displayed
-     * where on the screen is up-to-date.
-     */
-
-    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
-       UpdateDisplayInfo(textPtr);
-    }
-
-    /*
-     * If the coordinates are above the top of the window, then adjust them to
-     * refer to the upper-right corner of the window. If they're off to one
-     * side or the other, then adjust to the closest side.
-     */
-
-    if (y < dInfoPtr->y) {
-       y = dInfoPtr->y;
-       x = dInfoPtr->x;
-       nearby = 1;
-    }
-    if (x >= dInfoPtr->maxX) {
-       x = dInfoPtr->maxX - 1;
-       nearby = 1;
-    }
-    if (x < dInfoPtr->x) {
-       x = dInfoPtr->x;
-       nearby = 1;
-    }
-
-    /*
-     * Find the display line containing the desired y-coordinate.
-     */
-
-    if (dInfoPtr->dLinePtr == NULL) {
-       if (nearest != NULL) {
-           *nearest = 1;
-       }
-       *indexPtr = textPtr->topIndex;
-       return;
-    }
-    for (dlPtr = validDlPtr = dInfoPtr->dLinePtr;
-           y >= (dlPtr->y + dlPtr->height);
-           dlPtr = dlPtr->nextPtr) {
-       if (dlPtr->chunkPtr != NULL) {
-           validDlPtr = dlPtr;
-       }
-       if (dlPtr->nextPtr == NULL) {
-           /*
-            * Y-coordinate is off the bottom of the displayed text. Use the
-            * last character on the last line.
-            */
-
-           x = dInfoPtr->maxX - 1;
-           nearby = 1;
-           break;
-       }
-    }
-    if (dlPtr->chunkPtr == NULL) {
-       dlPtr = validDlPtr;
-    }
-
-    if (nearest != NULL) {
-       *nearest = nearby;
-    }
-
-    DlineIndexOfX(textPtr, dlPtr, x, indexPtr);
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * DlineIndexOfX --
- *
- *     Given an x coordinate in a display line, find the index of the
- *     character closest to that location.
- *
- *     This is effectively the opposite of DlineXOfIndex.
- *
- * Results:
- *     The index at *indexPtr is modified to refer to the character on the
- *     display line that is closest to x.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-DlineIndexOfX(
-    TkText *textPtr,           /* Widget record for text widget. */
-    DLine *dlPtr,              /* Display information for this display
-                                * line. */
-    int x,                     /* Pixel x coordinate of point in widget's
-                                * window. */
-    TkTextIndex *indexPtr)     /* This index gets filled in with the index of
-                                * the character nearest to x. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    register TkTextDispChunk *chunkPtr;
-
-    /*
-     * Scan through the line's chunks to find the one that contains the
-     * desired x-coordinate. Before doing this, translate the x-coordinate
-     * from the coordinate system of the window to the coordinate system of
-     * the line (to take account of x-scrolling).
-     */
-
-    *indexPtr = dlPtr->index;
-    x = x - dInfoPtr->x + dInfoPtr->curXPixelOffset;
-    chunkPtr = dlPtr->chunkPtr;
-
-    if (chunkPtr == NULL || x == 0) {
-       /*
-        * This may occur if everything is elided, or if we're simply already
-        * at the beginning of the line.
-        */
-
-       return;
-    }
-
-    while (x >= (chunkPtr->x + chunkPtr->width)) {
-       /*
-        * Note that this forward then backward movement of the index can be
-        * problematic at the end of the buffer (we can't move forward, and
-        * then when we move backward, we do, leading to the wrong position).
-        * Hence when x == 0 we take special action above.
-        */
-
-       if (TkTextIndexForwBytes(NULL,indexPtr,chunkPtr->numBytes,indexPtr)) {
-           /*
-            * We've reached the end of the text.
-            */
-
-            TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr, COUNT_INDICES);
-           return;
-       }
-       if (chunkPtr->nextPtr == NULL) {
-           /*
-            * We've reached the end of the display line.
-            */
-
-            TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr, COUNT_INDICES);
-           return;
-       }
-       chunkPtr = chunkPtr->nextPtr;
-    }
-
-    /*
-     * If the chunk has more than one byte in it, ask it which character is at
-     * the desired location. In this case we can manipulate
-     * 'indexPtr->byteIndex' directly, because we know we're staying inside a
-     * single logical line.
-     */
-
-    if (chunkPtr->numBytes > 1) {
-       indexPtr->byteIndex += chunkPtr->measureProc(chunkPtr, x);
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextIndexOfX --
- *
- *     Given a logical x coordinate (i.e. distance in pixels from the
- *     beginning of the display line, not taking into account any information
- *     about the window, scrolling etc.) on the display line starting with
- *     the given index, adjust that index to refer to the object under the x
- *     coordinate.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkTextIndexOfX(
-    TkText *textPtr,           /* Widget record for text widget. */
-    int x,                     /* The x coordinate for which we want the
-                                * index. */
-    TkTextIndex *indexPtr)     /* Index of display line start, which will be
-                                * adjusted to the index under the given x
-                                * coordinate. */
-{
-    DLine *dlPtr = LayoutDLine(textPtr, indexPtr);
-    DlineIndexOfX(textPtr, dlPtr, x + textPtr->dInfoPtr->x
-               - textPtr->dInfoPtr->curXPixelOffset, indexPtr);
-    FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP);
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * DlineXOfIndex --
- *
- *     Given a relative byte index on a given display line (i.e. the number
- *     of byte indices from the beginning of the given display line), find
- *     the x coordinate of that index within the abstract display line,
- *     without adjusting for the x-scroll state of the line.
- *
- *     This is effectively the opposite of DlineIndexOfX.
- *
- *     NB. The 'byteIndex' is relative to the display line, NOT the logical
- *     line.
- *
- * Results:
- *     The x coordinate.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-DlineXOfIndex(
-    TkText *textPtr,           /* Widget record for text widget. */
-    DLine *dlPtr,              /* Display information for this display
-                                * line. */
-    int byteIndex)             /* The byte index for which we want the
-                                * coordinate. */
-{
-    register TkTextDispChunk *chunkPtr = dlPtr->chunkPtr;
-    int x = 0;
-
-    if (byteIndex == 0 || chunkPtr == NULL) {
-       return x;
-    }
-
-    /*
-     * Scan through the line's chunks to find the one that contains the
-     * desired byte index.
-     */
-
-    chunkPtr = dlPtr->chunkPtr;
-    while (byteIndex > 0) {
-       if (byteIndex < chunkPtr->numBytes) {
-           int y, width, height;
-
-           chunkPtr->bboxProc(textPtr, chunkPtr, byteIndex,
-                   dlPtr->y + dlPtr->spaceAbove,
-                   dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
-                   dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width,
-                   &height);
-           break;
-       }
-       byteIndex -= chunkPtr->numBytes;
-       if (chunkPtr->nextPtr == NULL || byteIndex == 0) {
-           x = chunkPtr->x + chunkPtr->width;
-           break;
-       }
-       chunkPtr = chunkPtr->nextPtr;
-    }
-
-    return x;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextIndexBbox --
- *
- *     Given an index, find the bounding box of the screen area occupied by
- *     the entity (character, window, image) at that index.
- *
- * Results:
- *     Zero is returned if the index is on the screen. -1 means the index is
- *     not on the screen. If the return value is 0, then the bounding box of
- *     the part of the index that's visible on the screen is returned to
- *     *xPtr, *yPtr, *widthPtr, and *heightPtr.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkTextIndexBbox(
-    TkText *textPtr,           /* Widget record for text widget. */
-    const TkTextIndex *indexPtr,/* Index whose bounding box is desired. */
-    int *xPtr, int *yPtr,      /* Filled with index's upper-left
-                                * coordinate. */
-    int *widthPtr, int *heightPtr,
-                               /* Filled in with index's dimensions. */
-    int *charWidthPtr)         /* If the 'index' is at the end of a display
-                                * line and therefore takes up a very large
-                                * width, this is used to return the smaller
-                                * width actually desired by the index. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    DLine *dlPtr;
-    register TkTextDispChunk *chunkPtr;
-    int byteCount;
-
-    /*
-     * Make sure that all of the screen layout information is up to date.
-     */
-
-    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
-       UpdateDisplayInfo(textPtr);
-    }
-
-    /*
-     * Find the display line containing the desired index.
-     */
-
-    dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
-
-    /* 
-     * Two cases shall be trapped here because the logic later really
-     * needs dlPtr to be the display line containing indexPtr:
-     *   1. if no display line contains the desired index (NULL dlPtr)
-     *   2. if indexPtr is before the first display line, in which case
-     *      dlPtr currently points to the first display line
-     */
-
-    if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) {
-       return -1;
-    }
-
-    /*
-     * Find the chunk within the display line that contains the desired
-     * index. The chunks making the display line are skipped up to but not
-     * including the one crossing indexPtr. Skipping is done based on
-     * a byteCount offset possibly spanning several logical lines in case
-     * they are elided.
-     */
-
-    byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, indexPtr);
-    for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) {
-       if (chunkPtr == NULL) {
-           return -1;
-       }
-       if (byteCount < chunkPtr->numBytes) {
-           break;
-       }
-       byteCount -= chunkPtr->numBytes;
-    }
-
-    /*
-     * Call a chunk-specific function to find the horizontal range of the
-     * character within the chunk, then fill in the vertical range. The
-     * x-coordinate returned by bboxProc is a coordinate within a line, not a
-     * coordinate on the screen. Translate it to reflect horizontal scrolling.
-     */
-
-    chunkPtr->bboxProc(textPtr, chunkPtr, byteCount,
-           dlPtr->y + dlPtr->spaceAbove,
-           dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
-           dlPtr->baseline - dlPtr->spaceAbove, xPtr, yPtr, widthPtr,
-           heightPtr);
-    *xPtr = *xPtr + dInfoPtr->x - dInfoPtr->curXPixelOffset;
-    if ((byteCount == chunkPtr->numBytes-1) && (chunkPtr->nextPtr == NULL)) {
-       /*
-        * Last character in display line. Give it all the space up to the
-        * line.
-        */
-
-       if (charWidthPtr != NULL) {
-           *charWidthPtr = dInfoPtr->maxX - *xPtr;
-            if (*charWidthPtr > textPtr->charWidth) {
-                *charWidthPtr = textPtr->charWidth;
-            }
-       }
-       if (*xPtr > dInfoPtr->maxX) {
-           *xPtr = dInfoPtr->maxX;
-       }
-       *widthPtr = dInfoPtr->maxX - *xPtr;
-    } else {
-       if (charWidthPtr != NULL) {
-           *charWidthPtr = *widthPtr;
-       }
-    }
-    if (*widthPtr == 0) {
-       /*
-        * With zero width (e.g. elided text) we just need to make sure it is
-        * onscreen, where the '=' case here is ok.
-        */
-
-       if (*xPtr < dInfoPtr->x) {
-           return -1;
-       }
-    } else {
-       if ((*xPtr + *widthPtr) <= dInfoPtr->x) {
-           return -1;
-       }
-    }
-    if ((*xPtr + *widthPtr) > dInfoPtr->maxX) {
-       *widthPtr = dInfoPtr->maxX - *xPtr;
-       if (*widthPtr <= 0) {
-           return -1;
-       }
-    }
-    if ((*yPtr + *heightPtr) > dInfoPtr->maxY) {
-       *heightPtr = dInfoPtr->maxY - *yPtr;
-       if (*heightPtr <= 0) {
-           return -1;
-       }
-    }
-    return 0;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TkTextDLineInfo --
- *
- *     Given an index, return information about the display line containing
- *     that character.
- *
- * Results:
- *     Zero is returned if the character is on the screen. -1 means the
- *     character isn't on the screen. If the return value is 0, then
- *     information is returned in the variables pointed to by xPtr, yPtr,
- *     widthPtr, heightPtr, and basePtr.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkTextDLineInfo(
-    TkText *textPtr,           /* Widget record for text widget. */
-    const TkTextIndex *indexPtr,/* Index of character whose bounding box is
-                                * desired. */
-    int *xPtr, int *yPtr,      /* Filled with line's upper-left
-                                * coordinate. */
-    int *widthPtr, int *heightPtr,
-                               /* Filled in with line's dimensions. */
-    int *basePtr)              /* Filled in with the baseline position,
-                                * measured as an offset down from *yPtr. */
-{
-    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
-    DLine *dlPtr;
-    int dlx;
-
-    /*
-     * Make sure that all of the screen layout information is up to date.
-     */
-
-    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
-       UpdateDisplayInfo(textPtr);
-    }
-
-    /*
-     * Find the display line containing the desired index.
-     */
-
-    dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
-
-    /* 
-     * Two cases shall be trapped here because the logic later really
-     * needs dlPtr to be the display line containing indexPtr:
-     *   1. if no display line contains the desired index (NULL dlPtr)
-     *   2. if indexPtr is before the first display line, in which case
-     *      dlPtr currently points to the first display line
-     */
-
-    if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) {
-       return -1;
-    }
-
-    dlx = (dlPtr->chunkPtr != NULL? dlPtr->chunkPtr->x: 0);
-    *xPtr = dInfoPtr->x - dInfoPtr->curXPixelOffset + dlx;
-    *widthPtr = dlPtr->length - dlx;
-    *yPtr = dlPtr->y;
-    if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) {
-       *heightPtr = dInfoPtr->maxY - dlPtr->y;
-    } else {
-       *heightPtr = dlPtr->height;
-    }
-    *basePtr = dlPtr->baseline;
-    return 0;
-}
-\f
-/*
- * Get bounding-box information about an elided chunk.
- */
-
-static void
-ElideBboxProc(
-    TkText *textPtr,
-    TkTextDispChunk *chunkPtr, /* Chunk containing desired char. */
-    int index,                 /* Index of desired character within the
-                                * chunk. */
-    int y,                     /* Topmost pixel in area allocated for this
-                                * line. */
-    int lineHeight,            /* Height of line, in pixels. */
-    int baseline,              /* Location of line's baseline, in pixels
-                                * measured down from y. */
-    int *xPtr, int *yPtr,      /* Gets filled in with coords of character's
-                                * upper-left pixel. X-coord is in same
-                                * coordinate system as chunkPtr->x. */
-    int *widthPtr,             /* Gets filled in with width of character, in
-                                * pixels. */
-    int *heightPtr)            /* Gets filled in with height of character, in
-                                * pixels. */
-{
-    *xPtr = chunkPtr->x;
-    *yPtr = y;
-    *widthPtr = *heightPtr = 0;
-}
-\f
-/*
- * Measure an elided chunk.
- */
-
-static int
-ElideMeasureProc(
-    TkTextDispChunk *chunkPtr, /* Chunk containing desired coord. */
-    int x)                     /* X-coordinate, in same coordinate system as
-                                * chunkPtr->x. */
-{
-    return 0 /*chunkPtr->numBytes - 1*/;
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * TkTextCharLayoutProc --
- *
- *     This function is the "layoutProc" for character segments.
- *
- * Results:
- *     If there is something to display for the chunk then a non-zero value
- *     is returned and the fields of chunkPtr will be filled in (see the
- *     declaration of TkTextDispChunk in tkText.h for details). If zero is
- *     returned it means that no characters from this chunk fit in the
- *     window. If -1 is returned it means that this segment just doesn't need
- *     to be displayed (never happens for text).
- *
- * Side effects:
- *     Memory is allocated to hold additional information about the chunk.
- *
- *--------------------------------------------------------------
- */
-
-int
-TkTextCharLayoutProc(
-    TkText *textPtr,           /* Text widget being layed out. */
-    TkTextIndex *indexPtr,     /* Index of first character to lay out
-                                * (corresponds to segPtr and offset). */
-    TkTextSegment *segPtr,     /* Segment being layed out. */
-    int byteOffset,            /* Byte offset within segment of first
-                                * character to consider. */
-    int maxX,                  /* Chunk must not occupy pixels at this
-                                * position or higher. */
-    int maxBytes,              /* Chunk must not include more than this many
-                                * characters. */
-    int noCharsYet,            /* Non-zero means no characters have been
-                                * assigned to this display line yet. */
-    TkWrapMode wrapMode,       /* How to handle line wrapping:
-                                * TEXT_WRAPMODE_CHAR, TEXT_WRAPMODE_NONE, or
-                                * TEXT_WRAPMODE_WORD. */
-    register TkTextDispChunk *chunkPtr)
-                               /* Structure to fill in with information about
-                                * this chunk. The x field has already been
-                                * set by the caller. */
-{
-    Tk_Font tkfont;
-    int nextX, bytesThatFit, count;
-    CharInfo *ciPtr;
-    char *p;
-    TkTextSegment *nextPtr;
-    Tk_FontMetrics fm;
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-    const char *line;
-    int lineOffset;
-    BaseCharInfo *bciPtr;
-    Tcl_DString *baseString;
-#endif
-
-    /*
-     * Figure out how many characters will fit in the space we've got. Include
-     * the next character, even though it won't fit completely, if any of the
-     * following is true:
-     *  (a) the chunk contains no characters and the display line contains no
-     *      characters yet (i.e. the line isn't wide enough to hold even a
-     *      single character).
-     *  (b) at least one pixel of the character is visible, we have not
-     *      already exceeded the character limit, and the next character is a
-     *      white space character.
-     */
-
-    p = segPtr->body.chars + byteOffset;
-    tkfont = chunkPtr->stylePtr->sValuePtr->tkfont;
-
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-    if (baseCharChunkPtr == NULL) {
-       baseCharChunkPtr = chunkPtr;
-       bciPtr = ckalloc(sizeof(BaseCharInfo));
-       baseString = &bciPtr->baseChars;
-       Tcl_DStringInit(baseString);
-       bciPtr->width = 0;
-
-       ciPtr = &bciPtr->ci;
-    } else {
-       bciPtr = baseCharChunkPtr->clientData;
-       ciPtr = ckalloc(sizeof(CharInfo));
-       baseString = &bciPtr->baseChars;
-    }
-
-    lineOffset = Tcl_DStringLength(baseString);
-    line = Tcl_DStringAppend(baseString,p,maxBytes);
-
-    chunkPtr->clientData = ciPtr;
-    ciPtr->baseChunkPtr = baseCharChunkPtr;
-    ciPtr->baseOffset = lineOffset;
-    ciPtr->chars = NULL;
-    ciPtr->numBytes = 0;
-
-    bytesThatFit = CharChunkMeasureChars(chunkPtr, line,
-           lineOffset + maxBytes, lineOffset, -1, chunkPtr->x, maxX,
-           TK_ISOLATE_END, &nextX);
-#else /* !TK_LAYOUT_WITH_BASE_CHUNKS */
-    bytesThatFit = CharChunkMeasureChars(chunkPtr, p, maxBytes, 0, -1,
-           chunkPtr->x, maxX, TK_ISOLATE_END, &nextX);
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-
-    if (bytesThatFit < maxBytes) {
-       if ((bytesThatFit == 0) && noCharsYet) {
-           Tcl_UniChar ch;
-           int chLen = Tcl_UtfToUniChar(p, &ch);
-
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-           bytesThatFit = CharChunkMeasureChars(chunkPtr, line,
-                   lineOffset+chLen, lineOffset, -1, chunkPtr->x, -1, 0,
-                   &nextX);
-#else /* !TK_LAYOUT_WITH_BASE_CHUNKS */
-           bytesThatFit = CharChunkMeasureChars(chunkPtr, p, chLen, 0, -1,
-                   chunkPtr->x, -1, 0, &nextX);
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-       }
-       if ((nextX < maxX) && ((p[bytesThatFit] == ' ')
-               || (p[bytesThatFit] == '\t'))) {
-           /*
-            * Space characters are funny, in that they are considered to fit
-            * if there is at least one pixel of space left on the line. Just
-            * give the space character whatever space is left.
-            */
-
-           nextX = maxX;
-           bytesThatFit++;
-       }
-       if (p[bytesThatFit] == '\n') {
-           /*
-            * A newline character takes up no space, so if the previous
-            * character fits then so does the newline.
-            */
-
-           bytesThatFit++;
-       }
-       if (bytesThatFit == 0) {
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-           chunkPtr->clientData = NULL;
-           if (chunkPtr == baseCharChunkPtr) {
-               baseCharChunkPtr = NULL;
-               Tcl_DStringFree(baseString);
-           } else {
-               Tcl_DStringSetLength(baseString,lineOffset);
-           }
-           ckfree(ciPtr);
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-           return 0;
-       }
-    }
-
-    Tk_GetFontMetrics(tkfont, &fm);
-
-    /*
-     * Fill in the chunk structure and allocate and initialize a CharInfo
-     * structure. If the last character is a newline then don't bother to
-     * display it.
-     */
-
-    chunkPtr->displayProc = CharDisplayProc;
-    chunkPtr->undisplayProc = CharUndisplayProc;
-    chunkPtr->measureProc = CharMeasureProc;
-    chunkPtr->bboxProc = CharBboxProc;
-    chunkPtr->numBytes = bytesThatFit;
-    chunkPtr->minAscent = fm.ascent + chunkPtr->stylePtr->sValuePtr->offset;
-    chunkPtr->minDescent = fm.descent - chunkPtr->stylePtr->sValuePtr->offset;
-    chunkPtr->minHeight = 0;
-    chunkPtr->width = nextX - chunkPtr->x;
-    chunkPtr->breakIndex = -1;
-
-#if !TK_LAYOUT_WITH_BASE_CHUNKS
-    ciPtr = ckalloc((Tk_Offset(CharInfo, chars) + 1) + bytesThatFit);
-    chunkPtr->clientData = ciPtr;
-    memcpy(ciPtr->chars, p, (unsigned) bytesThatFit);
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-
-    ciPtr->numBytes = bytesThatFit;
-    if (p[bytesThatFit - 1] == '\n') {
-       ciPtr->numBytes--;
-    }
-
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-    /*
-     * Final update for the current base chunk data.
-     */
-
-    Tcl_DStringSetLength(baseString,lineOffset+ciPtr->numBytes);
-    bciPtr->width = nextX - baseCharChunkPtr->x;
-
-    /*
-     * Finalize the base chunk if this chunk ends in a tab, which definitly
-     * breaks the context and needs to be handled on a higher level.
-     */
-
-    if (ciPtr->numBytes > 0 && p[ciPtr->numBytes - 1] == '\t') {
-       FinalizeBaseChunk(chunkPtr);
-    }
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-
-    /*
-     * Compute a break location. If we're in word wrap mode, a break can occur
-     * after any space character, or at the end of the chunk if the next
-     * segment (ignoring those with zero size) is not a character segment.
-     */
-
-    if (wrapMode != TEXT_WRAPMODE_WORD) {
-       chunkPtr->breakIndex = chunkPtr->numBytes;
-    } else {
-       for (count = bytesThatFit, p += bytesThatFit - 1; count > 0;
-               count--, p--) {
-           /*
-            * Don't use isspace(); effects are unpredictable and can lead to
-            * odd word-wrapping problems on some platforms. Also don't use
-            * Tcl_UniCharIsSpace here either, as it identifies non-breaking
-            * spaces as places to break. What we actually want is only the
-            * ASCII space characters, so use them explicitly...
-            */
-
-           switch (*p) {
-           case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
-               chunkPtr->breakIndex = count;
-               goto checkForNextChunk;
-           }
-       }
-    checkForNextChunk:
-       if ((bytesThatFit + byteOffset) == segPtr->size) {
-           for (nextPtr = segPtr->nextPtr; nextPtr != NULL;
-                   nextPtr = nextPtr->nextPtr) {
-               if (nextPtr->size != 0) {
-                   if (nextPtr->typePtr != &tkTextCharType) {
-                       chunkPtr->breakIndex = chunkPtr->numBytes;
-                   }
-                   break;
-               }
-           }
-       }
-    }
-    return 1;
-}
-\f
-/*
- *---------------------------------------------------------------------------
- *
- * CharChunkMeasureChars --
- *
- *     Determine the number of characters from a char chunk that will fit in
- *     the given horizontal span.
- *
- *     This is the same as MeasureChars (which see), but in the context of a
- *     char chunk, i.e. on a higher level of abstraction. Use this function
- *     whereever possible instead of plain MeasureChars, so that the right
- *     context is used automatically.
- *
- * Results:
- *     The return value is the number of bytes from the range of start to end
- *     in source that fit in the span given by startX and maxX. *nextXPtr is
- *     filled in with the x-coordinate at which the first character that
- *     didn't fit would be drawn, if it were to be drawn.
- *
- * Side effects:
- *     None.
- *--------------------------------------------------------------
- */
-
-static int
-CharChunkMeasureChars(
-    TkTextDispChunk *chunkPtr, /* Chunk from which to measure. */
-    const char *chars,         /* Chars to use, instead of the chunk's own.
-                                * Used by the layoutproc during chunk setup.
-                                * All other callers use NULL. Not
-                                * NUL-terminated. */
-    int charsLen,              /* Length of the "chars" parameter. */
-    int start, int end,                /* The range of chars to measure inside the
-                                * chunk (or inside the additional chars). */
-    int startX,                        /* Starting x coordinate where the measured
-                                * span will begin. */
-    int maxX,                  /* Maximum pixel width of the span. May be -1
-                                * for unlimited. */
-    int flags,                 /* Flags to pass to MeasureChars. */
-    int *nextXPtr)             /* The function puts the newly calculated
-                                * right border x-position of the span
-                                * here. */
-{
-    Tk_Font tkfont = chunkPtr->stylePtr->sValuePtr->tkfont;
-    CharInfo *ciPtr = chunkPtr->clientData;
-
-#if !TK_LAYOUT_WITH_BASE_CHUNKS
-    if (chars == NULL) {
-       chars = ciPtr->chars;
-       charsLen = ciPtr->numBytes;
-    }
-    if (end == -1) {
-       end = charsLen;
-    }
-
-    return MeasureChars(tkfont, chars, charsLen, start, end-start,
-           startX, maxX, flags, nextXPtr);
-#else /* TK_LAYOUT_WITH_BASE_CHUNKS */
-    {
-       int xDisplacement;
-       int fit, bstart = start, bend = end;
-
-       if (chars == NULL) {
-           Tcl_DString *baseChars = &((BaseCharInfo *)
-                   ciPtr->baseChunkPtr->clientData)->baseChars;
-
-           chars = Tcl_DStringValue(baseChars);
-           charsLen = Tcl_DStringLength(baseChars);
-           bstart += ciPtr->baseOffset;
-           if (bend == -1) {
-               bend = ciPtr->baseOffset + ciPtr->numBytes;
-           } else {
-               bend += ciPtr->baseOffset;
-           }
-       } else if (bend == -1) {
-           bend = charsLen;
-       }
-
-       if (bstart == ciPtr->baseOffset) {
-           xDisplacement = startX - chunkPtr->x;
-       } else {
-           int widthUntilStart = 0;
-
-           MeasureChars(tkfont, chars, charsLen, 0, bstart,
-                   0, -1, 0, &widthUntilStart);
-           xDisplacement = startX - widthUntilStart - chunkPtr->x;
-       }
-
-       fit = MeasureChars(tkfont, chars, charsLen, 0, bend,
-               ciPtr->baseChunkPtr->x + xDisplacement, maxX, flags, nextXPtr);
-
-       if (fit < bstart) {
-           return 0;
-       } else {
-           return fit - bstart;
-       }
-    }
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * CharDisplayProc --
- *
- *     This function is called to display a character chunk on the screen or
- *     in an off-screen pixmap.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Graphics are drawn.
- *
- *--------------------------------------------------------------
- */
-
-static void
-CharDisplayProc(
-    TkText *textPtr,
-    TkTextDispChunk *chunkPtr, /* Chunk that is to be drawn. */
-    int x,                     /* X-position in dst at which to draw this
-                                * chunk (may differ from the x-position in
-                                * the chunk because of scrolling). */
-    int y,                     /* Y-position at which to draw this chunk in
-                                * dst. */
-    int height,                        /* Total height of line. */
-    int baseline,              /* Offset of baseline from y. */
-    Display *display,          /* Display to use for drawing. */
-    Drawable dst,              /* Pixmap or window in which to draw chunk. */
-    int screenY)               /* Y-coordinate in text window that
-                                * corresponds to y. */
-{
-    CharInfo *ciPtr = chunkPtr->clientData;
-    const char *string;
-    TextStyle *stylePtr;
-    StyleValues *sValuePtr;
-    int numBytes, offsetBytes, offsetX;
-#if TK_DRAW_IN_CONTEXT
-    BaseCharInfo *bciPtr;
-#endif /* TK_DRAW_IN_CONTEXT */
-
-    if ((x + chunkPtr->width) <= 0) {
-       /*
-        * The chunk is off-screen.
-        */
-
-       return;
-    }
-
-#if TK_DRAW_IN_CONTEXT
-    bciPtr = ciPtr->baseChunkPtr->clientData;
-    numBytes = Tcl_DStringLength(&bciPtr->baseChars);
-    string = Tcl_DStringValue(&bciPtr->baseChars);
-
-#elif TK_LAYOUT_WITH_BASE_CHUNKS
-    if (ciPtr->baseChunkPtr != chunkPtr) {
-       /*
-        * Without context drawing only base chunks display their foreground.
-        */
-
-       return;
-    }
-
-    numBytes = Tcl_DStringLength(&((BaseCharInfo *) ciPtr)->baseChars);
-    string = ciPtr->chars;
-
-#else /* !TK_LAYOUT_WITH_BASE_CHUNKS */
-    numBytes = ciPtr->numBytes;
-    string = ciPtr->chars;
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-
-    stylePtr = chunkPtr->stylePtr;
-    sValuePtr = stylePtr->sValuePtr;
-
-    /*
-     * If the text sticks out way to the left of the window, skip over the
-     * characters that aren't in the visible part of the window. This is
-     * essential if x is very negative (such as less than 32K); otherwise
-     * overflow problems will occur in servers that use 16-bit arithmetic,
-     * like X.
-     */
-
-    offsetX = x;
-    offsetBytes = 0;
-    if (x < 0) {
-       offsetBytes = CharChunkMeasureChars(chunkPtr, NULL, 0, 0, -1,
-               x, 0, 0, &offsetX);
-    }
-
-    /*
-     * Draw the text, underline, and overstrike for this chunk.
-     */
-
-    if (!sValuePtr->elide && (numBytes > offsetBytes)
-           && (stylePtr->fgGC != None)) {
-#if TK_DRAW_IN_CONTEXT
-       int start = ciPtr->baseOffset + offsetBytes;
-       int len = ciPtr->numBytes - offsetBytes;
-       int xDisplacement = x - chunkPtr->x;
-
-       if ((len > 0) && (string[start + len - 1] == '\t')) {
-           len--;
-       }
-       if (len <= 0) {
-           return;
-       }
-
-       TkpDrawCharsInContext(display, dst, stylePtr->fgGC, sValuePtr->tkfont,
-               string, numBytes, start, len,
-               ciPtr->baseChunkPtr->x + xDisplacement,
-               y + baseline - sValuePtr->offset);
-
-       if (sValuePtr->underline) {
-           TkUnderlineCharsInContext(display, dst, stylePtr->fgGC,
-                   sValuePtr->tkfont, string, numBytes,
-                   ciPtr->baseChunkPtr->x + xDisplacement,
-                   y + baseline - sValuePtr->offset,
-                   start, start+len);
-       }
-       if (sValuePtr->overstrike) {
-           Tk_FontMetrics fm;
-
-           Tk_GetFontMetrics(sValuePtr->tkfont, &fm);
-           TkUnderlineCharsInContext(display, dst, stylePtr->fgGC,
-                   sValuePtr->tkfont, string, numBytes,
-                   ciPtr->baseChunkPtr->x + xDisplacement,
-                   y + baseline - sValuePtr->offset
-                           - fm.descent - (fm.ascent * 3) / 10,
-                   start, start+len);
-       }
-#else /* !TK_DRAW_IN_CONTEXT */
-       string += offsetBytes;
-       numBytes -= offsetBytes;
-
-       if ((numBytes > 0) && (string[numBytes - 1] == '\t')) {
-           numBytes--;
-       }
-       Tk_DrawChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, string,
-               numBytes, offsetX, y + baseline - sValuePtr->offset);
-       if (sValuePtr->underline) {
-           Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont,
-                   string, offsetX,
-                   y + baseline - sValuePtr->offset,
-                   0, numBytes);
-
-       }
-       if (sValuePtr->overstrike) {
-           Tk_FontMetrics fm;
-
-           Tk_GetFontMetrics(sValuePtr->tkfont, &fm);
-           Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont,
-                   string, offsetX,
-                   y + baseline - sValuePtr->offset
-                           - fm.descent - (fm.ascent * 3) / 10,
-                   0, numBytes);
-       }
-#endif /* TK_DRAW_IN_CONTEXT */
-    }
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * CharUndisplayProc --
- *
- *     This function is called when a character chunk is no longer going to
- *     be displayed. It frees up resources that were allocated to display the
- *     chunk.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     Memory and other resources get freed.
- *
- *--------------------------------------------------------------
- */
-
-static void
-CharUndisplayProc(
-    TkText *textPtr,           /* Overall information about text widget. */
-    TkTextDispChunk *chunkPtr) /* Chunk that is about to be freed. */
-{
-    CharInfo *ciPtr = chunkPtr->clientData;
-
-    if (ciPtr) {
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-       if (chunkPtr == ciPtr->baseChunkPtr) {
-           /*
-            * Basechunks are undisplayed first, when DLines are freed or
-            * partially freed, so this makes sure we don't access their data
-            * any more.
-            */
-
-           FreeBaseChunk(chunkPtr);
-       } else if (ciPtr->baseChunkPtr != NULL) {
-           /*
-            * When other char chunks are undisplayed, drop their characters
-            * from the base chunk. This usually happens, when they are last
-            * in a line and need to be re-layed out.
-            */
-
-           RemoveFromBaseChunk(chunkPtr);
-       }
-
-       ciPtr->baseChunkPtr = NULL;
-       ciPtr->chars = NULL;
-       ciPtr->numBytes = 0;
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-
-       ckfree(ciPtr);
-       chunkPtr->clientData = NULL;
-    }
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * CharMeasureProc --
- *
- *     This function is called to determine which character in a character
- *     chunk lies over a given x-coordinate.
- *
- * Results:
- *     The return value is the index *within the chunk* of the character that
- *     covers the position given by "x".
- *
- * Side effects:
- *     None.
- *
- *--------------------------------------------------------------
- */
-
-static int
-CharMeasureProc(
-    TkTextDispChunk *chunkPtr, /* Chunk containing desired coord. */
-    int x)                     /* X-coordinate, in same coordinate system as
-                                * chunkPtr->x. */
-{
-    int endX;
-
-    return CharChunkMeasureChars(chunkPtr, NULL, 0, 0, chunkPtr->numBytes-1,
-           chunkPtr->x, x, 0, &endX); /* CHAR OFFSET */
-}
-\f
-/*
- *--------------------------------------------------------------
- *
- * CharBboxProc --
- *
- *     This function is called to compute the bounding box of the area
- *     occupied by a single character.
- *
- * Results:
- *     There is no return value. *xPtr and *yPtr are filled in with the
- *     coordinates of the upper left corner of the character, and *widthPtr
- *     and *heightPtr are filled in with the dimensions of the character in
- *     pixels. Note: not all of the returned bbox is necessarily visible on
- *     the screen (the rightmost part might be off-screen to the right, and
- *     the bottommost part might be off-screen to the bottom).
- *
- * Side effects:
- *     None.
- *
- *--------------------------------------------------------------
- */
-
-static void
-CharBboxProc(
-    TkText *textPtr,
-    TkTextDispChunk *chunkPtr, /* Chunk containing desired char. */
-    int byteIndex,             /* Byte offset of desired character within the
-                                * chunk. */
-    int y,                     /* Topmost pixel in area allocated for this
-                                * line. */
-    int lineHeight,            /* Height of line, in pixels. */
-    int baseline,              /* Location of line's baseline, in pixels
-                                * measured down from y. */
-    int *xPtr, int *yPtr,      /* Gets filled in with coords of character's
-                                * upper-left pixel. X-coord is in same
-                                * coordinate system as chunkPtr->x. */
-    int *widthPtr,             /* Gets filled in with width of character, in
-                                * pixels. */
-    int *heightPtr)            /* Gets filled in with height of character, in
-                                * pixels. */
-{
-    CharInfo *ciPtr = chunkPtr->clientData;
-    int maxX;
-
-    maxX = chunkPtr->width + chunkPtr->x;
-    CharChunkMeasureChars(chunkPtr, NULL, 0, 0, byteIndex,
-           chunkPtr->x, -1, 0, xPtr);
-
-    if (byteIndex == ciPtr->numBytes) {
-       /*
-        * This situation only happens if the last character in a line is a
-        * space character, in which case it absorbs all of the extra space in
-        * the line (see TkTextCharLayoutProc).
-        */
-
-       *widthPtr = maxX - *xPtr;
-    } else if ((ciPtr->chars[byteIndex] == '\t')
-           && (byteIndex == ciPtr->numBytes - 1)) {
-       /*
-        * The desired character is a tab character that terminates a chunk;
-        * give it all the space left in the chunk.
-        */
-
-       *widthPtr = maxX - *xPtr;
-    } else {
-       CharChunkMeasureChars(chunkPtr, NULL, 0, byteIndex, byteIndex+1,
-               *xPtr, -1, 0, widthPtr);
-       if (*widthPtr > maxX) {
-           *widthPtr = maxX - *xPtr;
-       } else {
-           *widthPtr -= *xPtr;
-       }
-    }
-    *yPtr = y + baseline - chunkPtr->minAscent;
-    *heightPtr = chunkPtr->minAscent + chunkPtr->minDescent;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * AdjustForTab --
- *
- *     This function is called to move a series of chunks right in order to
- *     align them with a tab stop.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The width of chunkPtr gets adjusted so that it absorbs the extra space
- *     due to the tab. The x locations in all the chunks after chunkPtr are
- *     adjusted rightward to align with the tab stop given by tabArrayPtr and
- *     index.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-AdjustForTab(
-    TkText *textPtr,           /* Information about the text widget as a
-                                * whole. */
-    TkTextTabArray *tabArrayPtr,/* Information about the tab stops that apply
-                                * to this line. May be NULL to indicate
-                                * default tabbing (every 8 chars). */
-    int index,                 /* Index of current tab stop. */
-    TkTextDispChunk *chunkPtr) /* Chunk whose last character is the tab; the
-                                * following chunks contain information to be
-                                * shifted right. */
-{
-    int x, desired, delta, width, decimal, i, gotDigit;
-    TkTextDispChunk *chunkPtr2, *decimalChunkPtr;
-    CharInfo *ciPtr;
-    int tabX, spaceWidth;
-    const char *p;
-    TkTextTabAlign alignment;
-
-    if (chunkPtr->nextPtr == NULL) {
-       /*
-        * Nothing after the actual tab; just return.
-        */
-
-       return;
-    }
-
-    x = chunkPtr->nextPtr->x;
-
-    /*
-     * If no tab information has been given, assuming tab stops are at 8
-     * average-sized characters. Still ensure we respect the tabular versus
-     * wordprocessor tab style.
-     */
-
-    if ((tabArrayPtr == NULL) || (tabArrayPtr->numTabs == 0)) {
-       /*
-        * No tab information has been given, so use the default
-        * interpretation of tabs.
-        */
-
-       if (textPtr->tabStyle == TK_TEXT_TABSTYLE_TABULAR) {
-           int tabWidth = Tk_TextWidth(textPtr->tkfont, "0", 1) * 8;
-           if (tabWidth == 0) {
-               tabWidth = 1;
-           }
-
-           desired = tabWidth * (index + 1);
-       } else {
-           desired = NextTabStop(textPtr->tkfont, x, 0);
-       }
-
-       goto update;
-    }
-
-    if (index < tabArrayPtr->numTabs) {
-       alignment = tabArrayPtr->tabs[index].alignment;
-       tabX = tabArrayPtr->tabs[index].location;
-    } else {
-       /*
-        * Ran out of tab stops; compute a tab position by extrapolating from
-        * the last two tab positions.
-        */
-
-       tabX = (int) (tabArrayPtr->lastTab +
-               (index + 1 - tabArrayPtr->numTabs)*tabArrayPtr->tabIncrement +
-               0.5);
-       alignment = tabArrayPtr->tabs[tabArrayPtr->numTabs-1].alignment;
-    }
-
-    if (alignment == LEFT) {
-       desired = tabX;
-       goto update;
-    }
-
-    if ((alignment == CENTER) || (alignment == RIGHT)) {
-       /*
-        * Compute the width of all the information in the tab group, then use
-        * it to pick a desired location.
-        */
-
-       width = 0;
-       for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL;
-               chunkPtr2 = chunkPtr2->nextPtr) {
-           width += chunkPtr2->width;
-       }
-       if (alignment == CENTER) {
-           desired = tabX - width/2;
-       } else {
-           desired = tabX - width;
-       }
-       goto update;
-    }
-
-    /*
-     * Must be numeric alignment. Search through the text to be tabbed,
-     * looking for the last , or . before the first character that isn't a
-     * number, comma, period, or sign.
-     */
-
-    decimalChunkPtr = NULL;
-    decimal = gotDigit = 0;
-    for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL;
-           chunkPtr2 = chunkPtr2->nextPtr) {
-       if (chunkPtr2->displayProc != CharDisplayProc) {
-           continue;
-       }
-       ciPtr = chunkPtr2->clientData;
-       for (p = ciPtr->chars, i = 0; i < ciPtr->numBytes; p++, i++) {
-           if (isdigit(UCHAR(*p))) {
-               gotDigit = 1;
-           } else if ((*p == '.') || (*p == ',')) {
-               decimal = p-ciPtr->chars;
-               decimalChunkPtr = chunkPtr2;
-           } else if (gotDigit) {
-               if (decimalChunkPtr == NULL) {
-                   decimal = p-ciPtr->chars;
-                   decimalChunkPtr = chunkPtr2;
-               }
-               goto endOfNumber;
-           }
-       }
-    }
-
-  endOfNumber:
-    if (decimalChunkPtr != NULL) {
-       int curX;
-
-       ciPtr = decimalChunkPtr->clientData;
-       CharChunkMeasureChars(decimalChunkPtr, NULL, 0, 0, decimal,
-               decimalChunkPtr->x, -1, 0, &curX);
-       desired = tabX - (curX - x);
-       goto update;
-    }
-
-    /*
-     * There wasn't a decimal point. Right justify the text.
-     */
-
-    width = 0;
-    for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL;
-           chunkPtr2 = chunkPtr2->nextPtr) {
-       width += chunkPtr2->width;
-    }
-    desired = tabX - width;
-
-    /*
-     * Shift all of the chunks to the right so that the left edge is at the
-     * desired location, then expand the chunk containing the tab. Be sure
-     * that the tab occupies at least the width of a space character.
-     */
-
-  update:
-    delta = desired - x;
-    MeasureChars(textPtr->tkfont, " ", 1, 0, 1, 0, -1, 0, &spaceWidth);
-    if (delta < spaceWidth) {
-       delta = spaceWidth;
-    }
-    for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL;
-           chunkPtr2 = chunkPtr2->nextPtr) {
-       chunkPtr2->x += delta;
-    }
-    chunkPtr->width += delta;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * SizeOfTab --
- *
- *     This returns an estimate of the amount of white space that will be
- *     consumed by a tab.
- *
- * Results:
- *     The return value is the minimum number of pixels that will be occupied
- *     by the next tab of tabArrayPtr, assuming that the current position on
- *     the line is x and the end of the line is maxX. The 'next tab' is
- *     determined by a combination of the current position (x) which it must
- *     be equal to or beyond, and the tab count in indexPtr.
- *
- *     For numeric tabs, this is a conservative estimate. The return value is
- *     always >= 0.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-SizeOfTab(
-    TkText *textPtr,           /* Information about the text widget as a
-                                * whole. */
-    int tabStyle,              /* One of TK_TEXT_TABSTYLE_TABULAR
-                                * or TK_TEXT_TABSTYLE_WORDPROCESSOR. */
-    TkTextTabArray *tabArrayPtr,/* Information about the tab stops that apply
-                                * to this line. NULL means use default
-                                * tabbing (every 8 chars.) */
-    int *indexPtr,             /* Contains index of previous tab stop, will
-                                * be updated to reflect the number of stops
-                                * used. */
-    int x,                     /* Current x-location in line. */
-    int maxX)                  /* X-location of pixel just past the right
-                                * edge of the line. */
-{
-    int tabX, result, index, spaceWidth, tabWidth;
-    TkTextTabAlign alignment;
-
-    index = *indexPtr;
-
-    if ((tabArrayPtr == NULL) || (tabArrayPtr->numTabs == 0)) {
-       /*
-        * We're using a default tab spacing of 8 characters.
-        */
-
-       tabWidth = Tk_TextWidth(textPtr->tkfont, "0", 1) * 8;
-       if (tabWidth == 0) {
-           tabWidth = 1;
-       }
-    } else {
-       tabWidth = 0;           /* Avoid compiler error. */
-    }
-
-    do {
-       /*
-        * We were given the count before this tab, so increment it first.
-        */
-
-       index++;
-
-       if ((tabArrayPtr == NULL) || (tabArrayPtr->numTabs == 0)) {
-           /*
-            * We're using a default tab spacing calculated above.
-            */
-
-           tabX = tabWidth * (index + 1);
-           alignment = LEFT;
-       } else if (index < tabArrayPtr->numTabs) {
-           tabX = tabArrayPtr->tabs[index].location;
-           alignment = tabArrayPtr->tabs[index].alignment;
-       } else {
-           /*
-            * Ran out of tab stops; compute a tab position by extrapolating.
-            */
-
-           tabX = (int) (tabArrayPtr->lastTab
-                   + (index + 1 - tabArrayPtr->numTabs)
-                   * tabArrayPtr->tabIncrement + 0.5);
-           alignment = tabArrayPtr->tabs[tabArrayPtr->numTabs-1].alignment;
-       }
-
-       /*
-        * If this tab stop is before the current x position, then we have two
-        * cases:
-        *
-        * With 'wordprocessor' style tabs, we must obviously continue until
-        * we reach the text tab stop.
-        *
-        * With 'tabular' style tabs, we always use the index'th tab stop.
-        */
-    } while (tabX <= x && (tabStyle == TK_TEXT_TABSTYLE_WORDPROCESSOR));
-
-    /*
-     * Inform our caller of how many tab stops we've used up.
-     */
-
-    *indexPtr = index;
-
-    if (alignment == CENTER) {
-       /*
-        * Be very careful in the arithmetic below, because maxX may be the
-        * largest positive number: watch out for integer overflow.
-        */
-
-       if ((maxX-tabX) < (tabX - x)) {
-           result = (maxX - x) - 2*(maxX - tabX);
-       } else {
-           result = 0;
-       }
-       goto done;
-    }
-    if (alignment == RIGHT) {
-       result = 0;
-       goto done;
-    }
-
-    /*
-     * Note: this treats NUMERIC alignment the same as LEFT alignment, which
-     * is somewhat conservative. However, it's pretty tricky at this point to
-     * figure out exactly where the damn decimal point will be.
-     */
-
-    if (tabX > x) {
-       result = tabX - x;
-    } else {
-       result = 0;
-    }
-
-  done:
-    MeasureChars(textPtr->tkfont, " ", 1, 0, 1, 0, -1, 0, &spaceWidth);
-    if (result < spaceWidth) {
-       result = spaceWidth;
-    }
-    return result;
-}
-\f
-/*
- *---------------------------------------------------------------------------
- *
- * NextTabStop --
- *
- *     Given the current position, determine where the next default tab stop
- *     would be located. This function is called when the current chunk in
- *     the text has no tabs defined and so the default tab spacing for the
- *     font should be used, provided we are using wordprocessor style tabs.
- *
- * Results:
- *     The location in pixels of the next tab stop.
- *
- * Side effects:
- *     None.
- *
- *---------------------------------------------------------------------------
- */
-
-static int
-NextTabStop(
-    Tk_Font tkfont,            /* Font in which chunk that contains tab stop
-                                * will be drawn. */
-    int x,                     /* X-position in pixels where last character
-                                * was drawn. The next tab stop occurs
-                                * somewhere after this location. */
-    int tabOrigin)             /* The origin for tab stops. May be non-zero
-                                * if text has been scrolled. */
-{
-    int tabWidth, rem;
-
-    tabWidth = Tk_TextWidth(tkfont, "0", 1) * 8;
-    if (tabWidth == 0) {
-       tabWidth = 1;
-    }
-
-    x += tabWidth;
-    rem = (x - tabOrigin) % tabWidth;
-    if (rem < 0) {
-       rem += tabWidth;
-    }
-    x -= rem;
-    return x;
-}
-\f
-/*
- *---------------------------------------------------------------------------
- *
- * MeasureChars --
- *
- *     Determine the number of characters from the string that will fit in
- *     the given horizontal span. The measurement is done under the
- *     assumption that Tk_DrawChars will be used to actually display the
- *     characters.
- *
- *     If tabs are encountered in the string, they will be ignored (they
- *     should only occur as last character of the string anyway).
- *
- *     If a newline is encountered in the string, the line will be broken at
- *     that point.
- *
- * Results:
- *     The return value is the number of bytes from the range of start to end
- *     in source that fit in the span given by startX and maxX. *nextXPtr is
- *     filled in with the x-coordinate at which the first character that
- *     didn't fit would be drawn, if it were to be drawn.
- *
- * Side effects:
- *     None.
- *
- *--------------------------------------------------------------
- */
-
-static int
-MeasureChars(
-    Tk_Font tkfont,            /* Font in which to draw characters. */
-    const char *source,                /* Characters to be displayed. Need not be
-                                * NULL-terminated. */
-    int maxBytes,              /* Maximum # of bytes to consider from
-                                * source. */
-    int rangeStart, int rangeLength,
-                               /* Range of bytes to consider in source.*/
-    int startX,                        /* X-position at which first character will be
-                                * drawn. */
-    int maxX,                  /* Don't consider any character that would
-                                * cross this x-position. */
-    int flags,                 /* Flags to pass to Tk_MeasureChars. */
-    int *nextXPtr)             /* Return x-position of terminating character
-                                * here. */
-{
-    int curX, width, ch;
-    const char *special, *end, *start;
-
-    ch = 0;                    /* lint. */
-    curX = startX;
-    start = source + rangeStart;
-    end = start + rangeLength;
-    special = start;
-    while (start < end) {
-       if (start >= special) {
-           /*
-            * Find the next special character in the string.
-            */
-
-           for (special = start; special < end; special++) {
-               ch = *special;
-               if ((ch == '\t') || (ch == '\n')) {
-                   break;
-               }
-           }
-       }
-
-       /*
-        * Special points at the next special character (or the end of the
-        * string). Process characters between start and special.
-        */
-
-       if ((maxX >= 0) && (curX >= maxX)) {
-           break;
-       }
-#if TK_DRAW_IN_CONTEXT
-       start += TkpMeasureCharsInContext(tkfont, source, maxBytes,
-               start - source, special - start,
-               maxX >= 0 ? maxX - curX : -1, flags, &width);
-#else
-       (void) maxBytes;
-       start += Tk_MeasureChars(tkfont, start, special - start,
-               maxX >= 0 ? maxX - curX : -1, flags, &width);
-#endif /* TK_DRAW_IN_CONTEXT */
-       curX += width;
-       if (start < special) {
-           /*
-            * No more chars fit in line.
-            */
-
-           break;
-       }
-       if (special < end) {
-           if (ch != '\t') {
-               break;
-           }
-           start++;
-       }
-    }
-
-    *nextXPtr = curX;
-    return start - (source+rangeStart);
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * TextGetScrollInfoObj --
- *
- *     This function is invoked to parse "xview" and "yview" scrolling
- *     commands for text widgets using the new scrolling command syntax
- *     ("moveto" or "scroll" options). It extends the public
- *     Tk_GetScrollInfoObj function with the addition of "pixels" as a valid
- *     unit alongside "pages" and "units". It is a shame the core API isn't
- *     more flexible in this regard.
- *
- * Results:
- *     The return value is either TKTEXT_SCROLL_MOVETO, TKTEXT_SCROLL_PAGES,
- *     TKTEXT_SCROLL_UNITS, TKTEXT_SCROLL_PIXELS or TKTEXT_SCROLL_ERROR. This
- *     indicates whether the command was successfully parsed and what form
- *     the command took. If TKTEXT_SCROLL_MOVETO, *dblPtr is filled in with
- *     the desired position; if TKTEXT_SCROLL_PAGES, TKTEXT_SCROLL_PIXELS or
- *     TKTEXT_SCROLL_UNITS, *intPtr is filled in with the number of
- *     pages/pixels/lines to move (may be negative); if TKTEXT_SCROLL_ERROR,
- *     the interp's result contains an error message.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-TextGetScrollInfoObj(
-    Tcl_Interp *interp,                /* Used for error reporting. */
-    TkText *textPtr,           /* Information about the text widget. */
-    int objc,                  /* # arguments for command. */
-    Tcl_Obj *const objv[],     /* Arguments for command. */
-    double *dblPtr,            /* Filled in with argument "moveto" option, if
-                                * any. */
-    int *intPtr)               /* Filled in with number of pages or lines or
-                                * pixels to scroll, if any. */
-{
-    static const char *const subcommands[] = {
-       "moveto", "scroll", NULL
-    };
-    enum viewSubcmds {
-       VIEW_MOVETO, VIEW_SCROLL
-    };
-    static const char *const units[] = {
-       "units", "pages", "pixels", NULL
-    };
-    enum viewUnits {
-       VIEW_SCROLL_UNITS, VIEW_SCROLL_PAGES, VIEW_SCROLL_PIXELS
-    };
-    int index;
-
-    if (Tcl_GetIndexFromObjStruct(interp, objv[2], subcommands,
-           sizeof(char *), "option", 0, &index) != TCL_OK) {
-       return TKTEXT_SCROLL_ERROR;
-    }
-
-    switch ((enum viewSubcmds) index) {
-    case VIEW_MOVETO:
-       if (objc != 4) {
-           Tcl_WrongNumArgs(interp, 3, objv, "fraction");
-           return TKTEXT_SCROLL_ERROR;
-       }
-       if (Tcl_GetDoubleFromObj(interp, objv[3], dblPtr) != TCL_OK) {
-           return TKTEXT_SCROLL_ERROR;
-       }
-       return TKTEXT_SCROLL_MOVETO;
-    case VIEW_SCROLL:
-       if (objc != 5) {
-           Tcl_WrongNumArgs(interp, 3, objv, "number units|pages|pixels");
-           return TKTEXT_SCROLL_ERROR;
-       }
-       if (Tcl_GetIndexFromObjStruct(interp, objv[4], units,
-               sizeof(char *), "argument", 0, &index) != TCL_OK) {
-           return TKTEXT_SCROLL_ERROR;
-       }
-       switch ((enum viewUnits) index) {
-       case VIEW_SCROLL_PAGES:
-           if (Tcl_GetIntFromObj(interp, objv[3], intPtr) != TCL_OK) {
-               return TKTEXT_SCROLL_ERROR;
-           }
-           return TKTEXT_SCROLL_PAGES;
-       case VIEW_SCROLL_PIXELS:
-           if (Tk_GetPixelsFromObj(interp, textPtr->tkwin, objv[3],
-                   intPtr) != TCL_OK) {
-               return TKTEXT_SCROLL_ERROR;
-           }
-           return TKTEXT_SCROLL_PIXELS;
-       case VIEW_SCROLL_UNITS:
-           if (Tcl_GetIntFromObj(interp, objv[3], intPtr) != TCL_OK) {
-               return TKTEXT_SCROLL_ERROR;
-           }
-           return TKTEXT_SCROLL_UNITS;
-       }
-    }
-    Tcl_Panic("unexpected switch fallthrough");
-    return TKTEXT_SCROLL_ERROR;
-}
-\f
-#if TK_LAYOUT_WITH_BASE_CHUNKS
-/*
- *----------------------------------------------------------------------
- *
- * FinalizeBaseChunk --
- *
- *     This procedure makes sure that all the chunks of the stretch are
- *     up-to-date. It is invoked when the LayoutProc has been called for all
- *     chunks and the base chunk is stable.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The CharInfo.chars of all dependent chunks point into
- *     BaseCharInfo.baseChars for easy access (and compatibility).
- *
- *----------------------------------------------------------------------
- */
-
-static void
-FinalizeBaseChunk(
-    TkTextDispChunk *addChunkPtr)
-                               /* An additional chunk to add to the stretch,
-                                * even though it may not be in the linked
-                                * list yet. Used by the LayoutProc, otherwise
-                                * NULL. */
-{
-    const char *baseChars;
-    TkTextDispChunk *chunkPtr;
-    CharInfo *ciPtr;
-#if TK_DRAW_IN_CONTEXT
-    int widthAdjust = 0;
-    int newwidth;
-#endif /* TK_DRAW_IN_CONTEXT */
-
-    if (baseCharChunkPtr == NULL) {
-       return;
-    }
-
-    baseChars = Tcl_DStringValue(
-           &((BaseCharInfo *) baseCharChunkPtr->clientData)->baseChars);
-
-    for (chunkPtr = baseCharChunkPtr; chunkPtr != NULL;
-           chunkPtr = chunkPtr->nextPtr) {
-#if TK_DRAW_IN_CONTEXT
-       chunkPtr->x += widthAdjust;
-#endif /* TK_DRAW_IN_CONTEXT */
-
-       if (chunkPtr->displayProc != CharDisplayProc) {
-           continue;
-       }
-       ciPtr = chunkPtr->clientData;
-       if (ciPtr->baseChunkPtr != baseCharChunkPtr) {
-           break;
-       }
-       ciPtr->chars = baseChars + ciPtr->baseOffset;
-
-#if TK_DRAW_IN_CONTEXT
-       newwidth = 0;
-       CharChunkMeasureChars(chunkPtr, NULL, 0, 0, -1, 0, -1, 0, &newwidth);
-       if (newwidth != chunkPtr->width) {
-           widthAdjust += newwidth - chunkPtr->width;
-           chunkPtr->width = newwidth;
-       }
-#endif /* TK_DRAW_IN_CONTEXT */
-    }
-
-    if (addChunkPtr != NULL) {
-       ciPtr = addChunkPtr->clientData;
-       ciPtr->chars = baseChars + ciPtr->baseOffset;
-
-#if TK_DRAW_IN_CONTEXT
-       addChunkPtr->x += widthAdjust;
-       CharChunkMeasureChars(addChunkPtr, NULL, 0, 0, -1, 0, -1, 0,
-               &addChunkPtr->width);
-#endif /* TK_DRAW_IN_CONTEXT */
-    }
-
-    baseCharChunkPtr = NULL;
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * FreeBaseChunk --
- *
- *     This procedure makes sure that all the chunks of the stretch are
- *     disconnected from the base chunk and the base chunk specific data is
- *     freed. It is invoked from the UndisplayProc. The procedure doesn't
- *     ckfree the base chunk clientData itself, that's up to the main
- *     UndisplayProc.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The CharInfo.chars of all dependent chunks are set to NULL. Memory
- *     that belongs specifically to the base chunk is freed.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-FreeBaseChunk(
-    TkTextDispChunk *baseChunkPtr)
-                               /* The base chunk of the stretch and head of
-                                * the linked list. */
-{
-    TkTextDispChunk *chunkPtr;
-    CharInfo *ciPtr;
-
-    if (baseCharChunkPtr == baseChunkPtr) {
-       baseCharChunkPtr = NULL;
-    }
-
-    for (chunkPtr=baseChunkPtr; chunkPtr!=NULL; chunkPtr=chunkPtr->nextPtr) {
-       if (chunkPtr->undisplayProc != CharUndisplayProc) {
-           continue;
-       }
-       ciPtr = chunkPtr->clientData;
-       if (ciPtr->baseChunkPtr != baseChunkPtr) {
-           break;
-       }
-
-       ciPtr->baseChunkPtr = NULL;
-       ciPtr->chars = NULL;
-    }
-
-    if (baseChunkPtr) {
-       Tcl_DStringFree(&((BaseCharInfo *) baseChunkPtr->clientData)->baseChars);
-    }
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * IsSameFGStyle --
- *
- *     Compare the foreground attributes of two styles. Specifically must
- *     consider: foreground color, font, font style and font decorations,
- *     elide, "offset" and foreground stipple. Do *not* consider: background
- *     color, border, relief or background stipple.
- *
- *     If we use TkpDrawCharsInContext(), we also don't need to check
- *     foreground color, font decorations, elide, offset and foreground
- *     stipple, so all that is left is font (including font size and font
- *     style) and "offset".
- *
- * Results:
- *     1 if the two styles match, 0 otherwise.
- *
- * Side effects:
- *     None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-IsSameFGStyle(
-    TextStyle *style1,
-    TextStyle *style2)
-{
-    StyleValues *sv1;
-    StyleValues *sv2;
-
-    if (style1 == style2) {
-       return 1;
-    }
-
-#if !TK_DRAW_IN_CONTEXT
-    if (
-#ifdef MAC_OSX_TK
-           !TkMacOSXCompareColors(style1->fgGC->foreground,
-                   style2->fgGC->foreground)
-#else
-           style1->fgGC->foreground != style2->fgGC->foreground
-#endif
-           ) {
-       return 0;
-    }
-#endif /* !TK_DRAW_IN_CONTEXT */
-
-    sv1 = style1->sValuePtr;
-    sv2 = style2->sValuePtr;
-
-#if TK_DRAW_IN_CONTEXT
-    return sv1->tkfont == sv2->tkfont && sv1->offset == sv2->offset;
-#else
-    return sv1->tkfont == sv2->tkfont
-           && sv1->underline == sv2->underline
-           && sv1->overstrike == sv2->overstrike
-           && sv1->elide == sv2->elide
-           && sv1->offset == sv2->offset
-           && sv1->fgStipple == sv1->fgStipple;
-#endif /* TK_DRAW_IN_CONTEXT */
-}
-\f
-/*
- *----------------------------------------------------------------------
- *
- * RemoveFromBaseChunk --
- *
- *     This procedure removes a chunk from the stretch as a result of
- *     UndisplayProc. The chunk in question should be the last in a stretch.
- *     This happens during re-layouting of the break position.
- *
- * Results:
- *     None.
- *
- * Side effects:
- *     The characters that belong to this chunk are removed from the base
- *     chunk. It is assumed that LayoutProc and FinalizeBaseChunk are called
- *     next to repair any damage that this causes to the integrity of the
- *     stretch and the other chunks. For that reason the base chunk is also
- *     put into baseCharChunkPtr automatically, so that LayoutProc can resume
- *     correctly.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-RemoveFromBaseChunk(
-    TkTextDispChunk *chunkPtr) /* The chunk to remove from the end of the
-                                * stretch. */
-{
-    CharInfo *ciPtr;
-    BaseCharInfo *bciPtr;
-
-    if (chunkPtr->displayProc != CharDisplayProc) {
-#ifdef DEBUG_LAYOUT_WITH_BASE_CHUNKS
-       fprintf(stderr,"RemoveFromBaseChunk called with wrong chunk type\n");
-#endif
-       return;
-    }
-
-    /*
-     * Reinstitute this base chunk for re-layout.
-     */
-
-    ciPtr = chunkPtr->clientData;
-    baseCharChunkPtr = ciPtr->baseChunkPtr;
-
-    /*
-     * Remove the chunk data from the base chunk data.
-     */
-
-    bciPtr = baseCharChunkPtr->clientData;
-
-    if ((ciPtr->baseOffset + ciPtr->numBytes)
-           != Tcl_DStringLength(&bciPtr->baseChars)) {
-#ifdef DEBUG_LAYOUT_WITH_BASE_CHUNKS
-       fprintf(stderr,"RemoveFromBaseChunk called with wrong chunk "
-               "(not last)\n");
-#endif
-    }
-
-    Tcl_DStringSetLength(&bciPtr->baseChars, ciPtr->baseOffset);
-
-    /*
-     * Invalidate the stored pixel width of the base chunk.
-     */
-
-    bciPtr->width = -1;
-}
-#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
-\f
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */