Tk Source Code

Check-in [e8542fce]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Silence compiler warnings, especially signed/unsigned problems. The handling of inline functions (C99 support) has been improved. C99 support for Linux/UNIX enabled. Some preparations for older Visual Studio compilers. Minor fix of test case (the use of abbreviated commands may break future releases).
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | revised_text | tip-466
Files: files | file ages | folders
SHA1: e8542fce34ce0ec8ad91b0fff24341a2d852fc8f
User & Date: gcramer 2017-02-23 14:35:55
Context
2017-02-23
17:00
Fixed MSVC warning C4098: 'void' function returning a value check-in: 887724cd user: fvogel tags: revised_text, tip-466
14:35
Silence compiler warnings, especially signed/unsigned problems. The handling of inline functions (C99 support) has been improved. C99 support for Linux/UNIX enabled. Some preparations for older Visual Studio compilers. Minor fix of test case (the use of abbreviated commands may break future releases). check-in: e8542fce user: gcramer tags: revised_text, tip-466
2017-02-22
21:36
Remove this from previous commit. Not yet convinced that -DMODULE_SCOPE="" is the best or correct solution. check-in: 4d30798b user: fvogel tags: revised_text, tip-466
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tkAlloc.h.

16
17
18
19
20
21
22

23
24
25
26
27
28
29
30
31
32
33
34
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#ifndef _TK_ALLOC
#define _TK_ALLOC

#include "tcl.h"


#if TK_VALGRIND

# include <stdlib.h>

/* enables compiler check that these functions will not be used */
# undef ckalloc
# undef ckrealloc
# undef ckfree

#else /* if !TK_VALGRIND */








>



<
<







16
17
18
19
20
21
22
23
24
25
26


27
28
29
30
31
32
33
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#ifndef _TK_ALLOC
#define _TK_ALLOC

#include "tcl.h"
#include <stdlib.h>

#if TK_VALGRIND



/* enables compiler check that these functions will not be used */
# undef ckalloc
# undef ckrealloc
# undef ckfree

#else /* if !TK_VALGRIND */

Changes to generic/tkBitField.c.

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

#include "tkBitField.h"
#include "tkIntSet.h"
#include "tkAlloc.h"
#include <string.h>
#include <assert.h>

#if !(__STDC_VERSION__ >= 199901L)
# define _TK_NEED_IMPLEMENTATION
# include "tkBitFieldPriv.h"
#endif

#ifndef MAX
# define MAX(a,b) (((int) a) < ((int) b) ? b : a)
#endif







|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

#include "tkBitField.h"
#include "tkIntSet.h"
#include "tkAlloc.h"
#include <string.h>
#include <assert.h>

#ifndef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkBitFieldPriv.h"
#endif

#ifndef MAX
# define MAX(a,b) (((int) a) < ((int) b) ? b : a)
#endif
61
62
63
64
65
66
67
68
69
70
71
72
73
74

75
76
77
78
79
80

81



82
83
84
85
86
87
88
#  define MsbIndex(x) ((sizeof(unsigned long long)*8 - 1) - __builtin_clzll(x))

# else /* !(defined(__GNUC__) || defined(__clang__)) */

static unsigned
LsbIndex(uint64_t x)
{
    /* Source: http://chessprogramming.wikispaces.com/BitScan */
    static const unsigned MultiplyDeBruijnBitPosition[64] = {
	 0,  1, 48,  2, 57, 49, 28,  3, 61, 58, 50, 42, 38, 29, 17,  4,
	62, 55, 59, 36, 53, 51, 43, 22, 45, 39, 33, 30, 24, 18, 12,  5,
	63, 47, 56, 27, 60, 41, 37, 16, 54, 35, 52, 21, 44, 32, 23, 11,
	46, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19,  9, 13,  8,  7,  6
    };

    return MultiplyDeBruijnBitPosition[((uint64_t) ((x & -x)*UINT64_C(0x03f79d71b4cb0a89))) >> 58];
}

static unsigned
MsbIndex(uint64_t x)
{

    /* Source: http://stackoverflow.com/questions/671815/what-is-the-fastest-most-efficient-way-to-find-the-highest-set-bit-msb-in-an-i (extended to 64 bit by GC) */



   static const uint8_t Table[16] = { -1, 0, 1,1, 2,2,2,2, 3,3,3,3,3,3,3,3 };

   unsigned r = 0;
   uint64_t xk;

   if ((xk = x >> 32)) { r =  32; x = xk; }
   if ((xk = x >> 16)) { r += 16; x = xk; }







|






>
|





>
|
>
>
>







61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#  define MsbIndex(x) ((sizeof(unsigned long long)*8 - 1) - __builtin_clzll(x))

# else /* !(defined(__GNUC__) || defined(__clang__)) */

static unsigned
LsbIndex(uint64_t x)
{
    /* Source: http://chessprogramming.wikispaces.com/BitScan (adapted for MSVC) */
    static const unsigned MultiplyDeBruijnBitPosition[64] = {
	 0,  1, 48,  2, 57, 49, 28,  3, 61, 58, 50, 42, 38, 29, 17,  4,
	62, 55, 59, 36, 53, 51, 43, 22, 45, 39, 33, 30, 24, 18, 12,  5,
	63, 47, 56, 27, 60, 41, 37, 16, 54, 35, 52, 21, 44, 32, 23, 11,
	46, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19,  9, 13,  8,  7,  6
    };
    uint64_t idx = ((uint64_t) ((x & -((int64_t) x))*UINT64_C(0x03f79d71b4cb0a89))) >> 58;
    return MultiplyDeBruijnBitPosition[idx];
}

static unsigned
MsbIndex(uint64_t x)
{
    /*
     * Source: http://stackoverflow.com/questions/671815/what-is-the-fastest-most-efficient-way-to-find-the-highest-set-bit-msb-in-an-i
     * (extended to 64 bit by GC)
     */

   static const uint8_t Table[16] = { -1, 0, 1,1, 2,2,2,2, 3,3,3,3,3,3,3,3 };

   unsigned r = 0;
   uint64_t xk;

   if ((xk = x >> 32)) { r =  32; x = xk; }
   if ((xk = x >> 16)) { r += 16; x = xk; }
118
119
120
121
122
123
124

125


126
127
128
129
130
131
132
# else /* defined(__GNUC__) || defined(__clang__) */

#  if 1
/* On my system this is the fastest method, only about 5% slower than __builtin_ctz(). */
static unsigned
LsbIndex(uint32_t x)
{

    /* Source: http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear */


    static const unsigned MultiplyDeBruijnBitPosition[32] = {
	 0,  1, 28,  2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17,  4, 8,
	31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18,  6, 11,  5, 10, 9
    };
    return MultiplyDeBruijnBitPosition[((uint32_t) ((x & -((int32_t) x))*0x077cb531)) >> 27];
}
#  else







>
|
>
>







123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# else /* defined(__GNUC__) || defined(__clang__) */

#  if 1
/* On my system this is the fastest method, only about 5% slower than __builtin_ctz(). */
static unsigned
LsbIndex(uint32_t x)
{
    /*
     * Source: http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear
     * (adapted for MSVC)
     */
    static const unsigned MultiplyDeBruijnBitPosition[32] = {
	 0,  1, 28,  2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17,  4, 8,
	31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18,  6, 11,  5, 10, 9
    };
    return MultiplyDeBruijnBitPosition[((uint32_t) ((x & -((int32_t) x))*0x077cb531)) >> 27];
}
#  else
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
    TkBitField *bf)
{
    memset(bf->bits, 0xff, BYTE_SIZE(bf->size));
    ResetUnused(bf);
}


#if !NDEBUG

# include <stdio.h>

void
TkBitPrint(
    const TkBitField *bf)
{
    unsigned i;
    const char *comma = "";

    assert(bf);

    printf("%d:{ ", TkBitCount(bf));
    for (i = TkBitFindFirst(bf); i != TK_BIT_NPOS; i = TkBitFindNext(bf, i)) {
	printf("%s%d", comma, i);
	comma = ", ";
    }
    printf(" }\n");
}

#endif /* !NDEBUG */

#if TK_UNUSED_BITFIELD_FUNCTIONS

/*
 * These functions are not needed anymore, but shouldn't be removed, because sometimes
 * any of these functions might be useful.
 */







|




















|







1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
    TkBitField *bf)
{
    memset(bf->bits, 0xff, BYTE_SIZE(bf->size));
    ResetUnused(bf);
}


#ifndef NDEBUG

# include <stdio.h>

void
TkBitPrint(
    const TkBitField *bf)
{
    unsigned i;
    const char *comma = "";

    assert(bf);

    printf("%d:{ ", TkBitCount(bf));
    for (i = TkBitFindFirst(bf); i != TK_BIT_NPOS; i = TkBitFindNext(bf, i)) {
	printf("%s%d", comma, i);
	comma = ", ";
    }
    printf(" }\n");
}

#endif /* NDEBUG */

#if TK_UNUSED_BITFIELD_FUNCTIONS

/*
 * These functions are not needed anymore, but shouldn't be removed, because sometimes
 * any of these functions might be useful.
 */
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536

    return true;
}

#endif /* TK_UNUSED_BITFIELD_FUNCTIONS */


#if __STDC_VERSION__ >= 199901L
/* Additionally we need stand-alone object code. */
#define inline extern
inline TkBitField *TkBitNew(unsigned size);
inline const unsigned char *TkBitData(const TkBitField *bf);
inline unsigned TkBitByteSize(const TkBitField *bf);
inline unsigned TkBitRefCount(const TkBitField *bf);
inline void TkBitIncrRefCount(TkBitField *bf);
inline unsigned TkBitDecrRefCount(TkBitField *bf);
inline bool TkBitIsEmpty(const TkBitField *bf);
inline unsigned TkBitSize(const TkBitField *bf);
inline bool TkBitTest(const TkBitField *bf, unsigned n);
inline bool TkBitNone(const TkBitField *bf);
inline bool TkBitIntersects(const TkBitField *bf1, const TkBitField *bf2);
inline void TkBitSet(TkBitField *bf, unsigned n);
inline void TkBitUnset(TkBitField *bf, unsigned n);
inline void TkBitPut(TkBitField *bf, unsigned n, bool value);
inline unsigned TkBitAdjustSize(unsigned size);
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */







|

<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|


1517
1518
1519
1520
1521
1522
1523
1524
1525

1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543

    return true;
}

#endif /* TK_UNUSED_BITFIELD_FUNCTIONS */


#ifdef TK_C99_INLINE_SUPPORT
/* Additionally we need stand-alone object code. */

extern TkBitField *TkBitNew(unsigned size);
extern const unsigned char *TkBitData(const TkBitField *bf);
extern unsigned TkBitByteSize(const TkBitField *bf);
extern unsigned TkBitRefCount(const TkBitField *bf);
extern void TkBitIncrRefCount(TkBitField *bf);
extern unsigned TkBitDecrRefCount(TkBitField *bf);
extern bool TkBitIsEmpty(const TkBitField *bf);
extern unsigned TkBitSize(const TkBitField *bf);
extern bool TkBitTest(const TkBitField *bf, unsigned n);
extern bool TkBitNone(const TkBitField *bf);
extern bool TkBitIntersects(const TkBitField *bf1, const TkBitField *bf2);
extern void TkBitSet(TkBitField *bf, unsigned n);
extern void TkBitUnset(TkBitField *bf, unsigned n);
extern void TkBitPut(TkBitField *bf, unsigned n, bool value);
extern unsigned TkBitAdjustSize(unsigned size);
#endif /* TK_C99_INLINE_SUPPORT */

/* vi:set ts=8 sw=4: */

Changes to generic/tkBitField.h.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef _TK
#include "tk.h"
#endif

#include "tkBool.h"
#include <stdint.h>

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


#ifdef TCL_WIDE_INT_IS_LONG
typedef uint64_t TkBitWord;
#else
typedef uint32_t TkBitWord;
#endif








<
<
<
<
<
<







15
16
17
18
19
20
21






22
23
24
25
26
27
28
#ifndef _TK
#include "tk.h"
#endif

#include "tkBool.h"
#include <stdint.h>








#ifdef TCL_WIDE_INT_IS_LONG
typedef uint64_t TkBitWord;
#else
typedef uint32_t TkBitWord;
#endif

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
bool TkBitTestAndUnset(TkBitField *bf, unsigned n);
void TkBitFill(TkBitField *bf);
void TkBitClear(TkBitField *bf);

/* Return nearest multiple of TK_BIT_NBITS which is greater or equal to given argument. */
inline unsigned TkBitAdjustSize(unsigned size);

#if !NDEBUG
void TkBitPrint(const TkBitField *bf);
#endif

#if TK_CHECK_ALLOCS
void TkBitCheckAllocs();
#endif








|







130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
bool TkBitTestAndUnset(TkBitField *bf, unsigned n);
void TkBitFill(TkBitField *bf);
void TkBitClear(TkBitField *bf);

/* Return nearest multiple of TK_BIT_NBITS which is greater or equal to given argument. */
inline unsigned TkBitAdjustSize(unsigned size);

#ifndef NDEBUG
void TkBitPrint(const TkBitField *bf);
#endif

#if TK_CHECK_ALLOCS
void TkBitCheckAllocs();
#endif

169
170
171
172
173
174
175
176
177
178
179
180
181
182
    const TkBitField *add2, const TkBitField *sub2);
/* ((bf1 + (add - sub)) & add) == ((bf2 + (add - sub)) & add) */
bool TkBitInnerJoinDifferenceIsEqual(const TkBitField *bf1, const TkBitField *bf2,
    const TkBitField *add, const TkBitField *sub);

#endif /* TK_UNUSED_BITFIELD_FUNCTIONS */

#if __STDC_VERSION__ >= 199901L
# define _TK_NEED_IMPLEMENTATION
# include "tkBitFieldPriv.h"
#endif

#endif /* _TKBITFIELD */
/* vi:set ts=8 sw=4: */







|



<


163
164
165
166
167
168
169
170
171
172
173

174
175
    const TkBitField *add2, const TkBitField *sub2);
/* ((bf1 + (add - sub)) & add) == ((bf2 + (add - sub)) & add) */
bool TkBitInnerJoinDifferenceIsEqual(const TkBitField *bf1, const TkBitField *bf2,
    const TkBitField *add, const TkBitField *sub);

#endif /* TK_UNUSED_BITFIELD_FUNCTIONS */

#ifdef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkBitFieldPriv.h"
#endif

#endif /* _TKBITFIELD */
/* vi:set ts=8 sw=4: */

Changes to generic/tkBitFieldPriv.h.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#endif /* _TKBITFIELDPRIV */


#ifdef _TK_NEED_IMPLEMENTATION

#include <assert.h>

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


#define TK_BIT_WORD_INDEX(n)	((n) >> ((TK_BIT_NBITS + 128) >> 5))
#define TK_BIT_INDEX(n)		((n) & (TK_BIT_NBITS - 1))
#define TK_BIT_MASK(n)		(((TkBitWord) 1) << (n))
#define TK_BIT_COUNT_WORDS(n)	((n + TK_BIT_NBITS - 1)/TK_BIT_NBITS)









<
<
<
<
<
<







22
23
24
25
26
27
28






29
30
31
32
33
34
35
#endif /* _TKBITFIELDPRIV */


#ifdef _TK_NEED_IMPLEMENTATION

#include <assert.h>








#define TK_BIT_WORD_INDEX(n)	((n) >> ((TK_BIT_NBITS + 128) >> 5))
#define TK_BIT_INDEX(n)		((n) & (TK_BIT_NBITS - 1))
#define TK_BIT_MASK(n)		(((TkBitWord) 1) << (n))
#define TK_BIT_COUNT_WORDS(n)	((n + TK_BIT_NBITS - 1)/TK_BIT_NBITS)


201
202
203
204
205
206
207

208
209
210
211
{
    if (value) {
	TkBitSet(bf, n);
    } else {
	TkBitUnset(bf, n);
    }
}


#undef _TK_NEED_IMPLEMENTATION
#endif /* _TK_NEED_IMPLEMENTATION */
/* vi:set ts=8 sw=4: */







>




195
196
197
198
199
200
201
202
203
204
205
206
{
    if (value) {
	TkBitSet(bf, n);
    } else {
	TkBitUnset(bf, n);
    }
}


#undef _TK_NEED_IMPLEMENTATION
#endif /* _TK_NEED_IMPLEMENTATION */
/* vi:set ts=8 sw=4: */

Changes to generic/tkBool.h.

23
24
25
26
27
28
29
























30
31
enum { true = (int) 1, false = (int) 0 };
#endif

#ifdef __cplusplus
} /* extern "C" */
#endif

























#endif /* _TK_BOOL */
/* vi:set ts=8 sw=4: */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
enum { true = (int) 1, false = (int) 0 };
#endif

#ifdef __cplusplus
} /* extern "C" */
#endif


/*
 * For the text widget stuff (and related files) this is a basic header
 * file, so it's the appropriate place for the C99 inline support macros.
 */

#ifdef _MSC_VER
# if defined(include)
#  define TK_C99_INLINE_SUPPORT
# elif _MSC_VER >= 1400
#  define inline __inline
#  define TK_C99_INLINE_SUPPORT
#  define TK_C99_INLINE_DEFINED
# else
#  define inline
#  define TK_C99_INLINE_DEFINED
# endif
#elif __STDC_VERSION__ >= 199901L
# define TK_C99_INLINE_SUPPORT
#else
# define inline
# define TK_C99_INLINE_DEFINED
#endif

#endif /* _TK_BOOL */
/* vi:set ts=8 sw=4: */

Changes to generic/tkIntSet.c.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkIntSet.h"
#include "tkBitField.h"
#include "tkAlloc.h"

#if !(__STDC_VERSION__ >= 199901L)
# define _TK_NEED_IMPLEMENTATION
# include "tkIntSetPriv.h"
#endif

#include <string.h>
#include <assert.h>








|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkIntSet.h"
#include "tkBitField.h"
#include "tkAlloc.h"

#ifndef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkIntSetPriv.h"
#endif

#include <string.h>
#include <assert.h>

1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569

    return true;
}

#endif /* !TK_TEXT_DONT_USE_BITFIELDS */


#if !NDEBUG

# include <stdio.h>

void
TkIntSetPrint(
    const TkIntSet *set)
{







|







1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569

    return true;
}

#endif /* !TK_TEXT_DONT_USE_BITFIELDS */


#ifndef NDEBUG

# include <stdio.h>

void
TkIntSetPrint(
    const TkIntSet *set)
{
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
    for (i = 0; i < n; ++i) {
	printf("%s%d", comma, set->buf[i]);
	comma = ", ";
    }
    printf(" }\n");
}

#endif /* !NDEBUG */

#if TK_UNUSED_INTSET_FUNCTIONS

/*
 * These functions are not needed anymore, but shouldn't be removed, because sometimes
 * any of these functions might be useful.
 */







|







1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
    for (i = 0; i < n; ++i) {
	printf("%s%d", comma, set->buf[i]);
	comma = ", ";
    }
    printf(" }\n");
}

#endif /* NDEBUG */

#if TK_UNUSED_INTSET_FUNCTIONS

/*
 * These functions are not needed anymore, but shouldn't be removed, because sometimes
 * any of these functions might be useful.
 */
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151

    return true;
}

#endif /* TK_UNUSED_INTSET_FUNCTIONS */


#if __STDC_VERSION__ >= 199901L
/* Additionally we need stand-alone object code. */
#define inline extern
inline unsigned TkIntSetByteSize(const TkIntSet *set);
inline const unsigned char *TkIntSetData(const TkIntSet *set);
inline bool TkIntSetIsEmpty(const TkIntSet *set);
inline unsigned TkIntSetSize(const TkIntSet *set);
inline unsigned TkIntSetMax(const TkIntSet *set);
inline unsigned TkIntSetRefCount(const TkIntSet *set);
inline void TkIntSetIncrRefCount(TkIntSet *set);
inline unsigned TkIntSetDecrRefCount(TkIntSet *set);
inline TkIntSetType TkIntSetAccess(const TkIntSet *set, unsigned index);
inline bool TkIntSetTest(const TkIntSet *set, unsigned n);
inline bool TkIntSetNone(const TkIntSet *set);
inline bool TkIntSetAny(const TkIntSet *set);
inline bool TkIntSetIsEqual(const TkIntSet *set1, const TkIntSet *set2);
inline bool TkIntSetContains(const TkIntSet *set1, const TkIntSet *set2);
inline bool TkIntSetDisjunctive(const TkIntSet *set1, const TkIntSet *set2);
inline bool TkIntSetIntersects(const TkIntSet *set1, const TkIntSet *set2);
inline unsigned TkIntSetFindFirst(const TkIntSet *set);
inline unsigned TkIntSetFindNext(const TkIntSet *set);
inline TkIntSet *TkIntSetAddOrErase(TkIntSet *set, unsigned n, bool add);
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */







|

<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|



2120
2121
2122
2123
2124
2125
2126
2127
2128

2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150

    return true;
}

#endif /* TK_UNUSED_INTSET_FUNCTIONS */


#ifdef TK_C99_INLINE_SUPPORT
/* Additionally we need stand-alone object code. */

extern unsigned TkIntSetByteSize(const TkIntSet *set);
extern const unsigned char *TkIntSetData(const TkIntSet *set);
extern bool TkIntSetIsEmpty(const TkIntSet *set);
extern unsigned TkIntSetSize(const TkIntSet *set);
extern unsigned TkIntSetMax(const TkIntSet *set);
extern unsigned TkIntSetRefCount(const TkIntSet *set);
extern void TkIntSetIncrRefCount(TkIntSet *set);
extern unsigned TkIntSetDecrRefCount(TkIntSet *set);
extern TkIntSetType TkIntSetAccess(const TkIntSet *set, unsigned index);
extern bool TkIntSetTest(const TkIntSet *set, unsigned n);
extern bool TkIntSetNone(const TkIntSet *set);
extern bool TkIntSetAny(const TkIntSet *set);
extern bool TkIntSetIsEqual(const TkIntSet *set1, const TkIntSet *set2);
extern bool TkIntSetContains(const TkIntSet *set1, const TkIntSet *set2);
extern bool TkIntSetDisjunctive(const TkIntSet *set1, const TkIntSet *set2);
extern bool TkIntSetIntersects(const TkIntSet *set1, const TkIntSet *set2);
extern unsigned TkIntSetFindFirst(const TkIntSet *set);
extern unsigned TkIntSetFindNext(const TkIntSet *set);
extern TkIntSet *TkIntSetAddOrErase(TkIntSet *set, unsigned n, bool add);
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */

Changes to generic/tkIntSet.h.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdint.h>

#if defined(__GNUC__) || defined(__clang__)
# define __warn_unused__ __attribute__((warn_unused_result))
#else
# define __warn_unused__
#endif

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


struct TkBitField;


typedef uint32_t TkIntSetType;

/*







<
<
<
<
<
<
<







20
21
22
23
24
25
26







27
28
29
30
31
32
33
#include <stdint.h>

#if defined(__GNUC__) || defined(__clang__)
# define __warn_unused__ __attribute__((warn_unused_result))
#else
# define __warn_unused__
#endif








struct TkBitField;


typedef uint32_t TkIntSetType;

/*
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
TkIntSet *TkIntSetAdd(TkIntSet *set, unsigned n) __warn_unused__;
TkIntSet *TkIntSetErase(TkIntSet *set, unsigned n) __warn_unused__;
TkIntSet *TkIntSetTestAndSet(TkIntSet *set, unsigned n) __warn_unused__;
TkIntSet *TkIntSetTestAndUnset(TkIntSet *set, unsigned n) __warn_unused__;
inline TkIntSet *TkIntSetAddOrErase(TkIntSet *set, unsigned n, bool add) __warn_unused__;
TkIntSet *TkIntSetClear(TkIntSet *set) __warn_unused__;

#if !NDEBUG
void TkIntSetPrint(const TkIntSet *set);
#endif


#if TK_UNUSED_INTSET_FUNCTIONS

/*







|







139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
TkIntSet *TkIntSetAdd(TkIntSet *set, unsigned n) __warn_unused__;
TkIntSet *TkIntSetErase(TkIntSet *set, unsigned n) __warn_unused__;
TkIntSet *TkIntSetTestAndSet(TkIntSet *set, unsigned n) __warn_unused__;
TkIntSet *TkIntSetTestAndUnset(TkIntSet *set, unsigned n) __warn_unused__;
inline TkIntSet *TkIntSetAddOrErase(TkIntSet *set, unsigned n, bool add) __warn_unused__;
TkIntSet *TkIntSetClear(TkIntSet *set) __warn_unused__;

#ifndef NDEBUG
void TkIntSetPrint(const TkIntSet *set);
#endif


#if TK_UNUSED_INTSET_FUNCTIONS

/*
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
    const TkIntSet *add, const TkIntSet *sub);

#endif /* TK_UNUSED_INTSET_FUNCTIONS */


#undef __warn_unused__

#if __STDC_VERSION__ >= 199901L
# define _TK_NEED_IMPLEMENTATION
#include "tkIntSetPriv.h"
# undef _TK_NEED_IMPLEMENTATION
#endif

#endif /* _TKINTSET */
/* vi:set ts=8 sw=4: */







|

|
<

<


172
173
174
175
176
177
178
179
180
181

182

183
184
    const TkIntSet *add, const TkIntSet *sub);

#endif /* TK_UNUSED_INTSET_FUNCTIONS */


#undef __warn_unused__

#ifdef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkIntSetPriv.h"

#endif

#endif /* _TKINTSET */
/* vi:set ts=8 sw=4: */

Changes to generic/tkIntSetPriv.h.

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#endif /* _TKINTSETPRIV */


#ifdef _TK_NEED_IMPLEMENTATION

#include <assert.h>

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


extern TkIntSetType *
TkIntSetLowerBound(
    TkIntSetType *first,
    TkIntSetType *last,
    TkIntSetType value);








<
<
<
<
<
<







30
31
32
33
34
35
36






37
38
39
40
41
42
43
#endif /* _TKINTSETPRIV */


#ifdef _TK_NEED_IMPLEMENTATION

#include <assert.h>








extern TkIntSetType *
TkIntSetLowerBound(
    TkIntSetType *first,
    TkIntSetType *last,
    TkIntSetType value);

272
273
274
275
276
277
278

279
280
281
282
    TkIntSet *set,
    unsigned n,
    bool add)
{
    assert(set);
    return add ? TkIntSetAdd(set, n) : TkIntSetErase(set, n);
}


#undef _TK_NEED_IMPLEMENTATION
#endif /* _TK_NEED_IMPLEMENTATION */
/* vi:set ts=8 sw=4: */







>




266
267
268
269
270
271
272
273
274
275
276
277
    TkIntSet *set,
    unsigned n,
    bool add)
{
    assert(set);
    return add ? TkIntSetAdd(set, n) : TkIntSetErase(set, n);
}


#undef _TK_NEED_IMPLEMENTATION
#endif /* _TK_NEED_IMPLEMENTATION */
/* vi:set ts=8 sw=4: */

Changes to generic/tkQTree.c.

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkQTree.h"
#include "tkAlloc.h"

#if !(__STDC_VERSION__ >= 199901L)
# define _TK_NEED_IMPLEMENTATION
# include "tkQTreePriv.h"
#endif

#include <tcl.h>
#include <string.h>
#include <assert.h>







|







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkQTree.h"
#include "tkAlloc.h"

#ifndef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkQTreePriv.h"
#endif

#include <tcl.h>
#include <string.h>
#include <assert.h>
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146

    return cd.count;
}

#endif /* QTREE_SEARCH_RECTS_CONTAINING */


#if __STDC_VERSION__ >= 199901L
/* Additionally we need stand-alone object code. */
#define inline extern
inline bool TkQTreeRectIsEmpty(const TkQTreeRect *rect);
inline bool TkQTreeRectIsEqual(const TkQTreeRect *rect1, const TkQTreeRect *rect2);
inline bool TkQTreeRectContainsPoint(const TkQTreeRect *rect, TkQTreeCoord x, TkQTreeCoord y);
inline bool TkQTreeRectContainsRect(const TkQTreeRect *rect1, const TkQTreeRect *rect2);
inline bool TkQTreeRectIntersects(const TkQTreeRect *rect1, const TkQTreeRect *rect2);
inline TkQTreeRect *TkQTreeRectSet(TkQTreeRect *rect,
    TkQTreeCoord xmin, TkQTreeCoord ymin, TkQTreeCoord xmax, TkQTreeCoord ymax);
inline TkQTreeRect *TkQTreeRectTranslate(TkQTreeRect *rect, TkQTreeCoord dx, TkQTreeCoord dy);
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */







|

<
|
|
|
|
|
|

|



1126
1127
1128
1129
1130
1131
1132
1133
1134

1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145

    return cd.count;
}

#endif /* QTREE_SEARCH_RECTS_CONTAINING */


#ifdef TK_C99_INLINE_SUPPORT
/* Additionally we need stand-alone object code. */

extern bool TkQTreeRectIsEmpty(const TkQTreeRect *rect);
extern bool TkQTreeRectIsEqual(const TkQTreeRect *rect1, const TkQTreeRect *rect2);
extern bool TkQTreeRectContainsPoint(const TkQTreeRect *rect, TkQTreeCoord x, TkQTreeCoord y);
extern bool TkQTreeRectContainsRect(const TkQTreeRect *rect1, const TkQTreeRect *rect2);
extern bool TkQTreeRectIntersects(const TkQTreeRect *rect1, const TkQTreeRect *rect2);
extern TkQTreeRect *TkQTreeRectSet(TkQTreeRect *rect,
    TkQTreeCoord xmin, TkQTreeCoord ymin, TkQTreeCoord xmax, TkQTreeCoord ymax);
extern TkQTreeRect *TkQTreeRectTranslate(TkQTreeRect *rect, TkQTreeCoord dx, TkQTreeCoord dy);
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */

Changes to generic/tkQTree.h.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef _TKINT
#include "tkInt.h"
#endif

#include "tkBool.h"
#include <stdint.h>

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


/* =========================================================================
 * Definitions for rectangle support.
 * ========================================================================= */

typedef int32_t TkQTreeCoord;








<
<
<
<
<
<







15
16
17
18
19
20
21






22
23
24
25
26
27
28
#ifndef _TKINT
#include "tkInt.h"
#endif

#include "tkBool.h"
#include <stdint.h>








/* =========================================================================
 * Definitions for rectangle support.
 * ========================================================================= */

typedef int32_t TkQTreeCoord;

166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

unsigned TkQTreeSearchRectsContaining(const TkQTree tree, const TkQTreeRect *rect,
    TkQTreeCallback cbHit, TkQTreeClientData cbArg);

#endif /* QTREE_SEARCH_RECTS_CONTAINING */


#if __STDC_VERSION__ >= 199901L
# define _TK_NEED_IMPLEMENTATION
#include "tkQTreePriv.h"
# undef _TK_NEED_IMPLEMENTATION
#endif

#endif /* _TKQTREE */
/* vi:set ts=8 sw=4: */







|

|
<

<


160
161
162
163
164
165
166
167
168
169

170

171
172

unsigned TkQTreeSearchRectsContaining(const TkQTree tree, const TkQTreeRect *rect,
    TkQTreeCallback cbHit, TkQTreeClientData cbArg);

#endif /* QTREE_SEARCH_RECTS_CONTAINING */


#ifdef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkQTreePriv.h"

#endif

#endif /* _TKQTREE */
/* vi:set ts=8 sw=4: */

Changes to generic/tkQTreePriv.h.

14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#endif


#ifdef _TK_NEED_IMPLEMENTATION

#include <assert.h>

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


inline
bool
TkQTreeRectIsEmpty(
    const TkQTreeRect *rect)
{
    assert(rect);







<
<
<
<
<
<







14
15
16
17
18
19
20






21
22
23
24
25
26
27
#endif


#ifdef _TK_NEED_IMPLEMENTATION

#include <assert.h>








inline
bool
TkQTreeRectIsEmpty(
    const TkQTreeRect *rect)
{
    assert(rect);
155
156
157
158
159
160
161

162
163
164
165
    rect->xmin += dx;
    rect->xmax += dx;
    rect->ymin += dy;
    rect->ymax += dy;

    return rect;
}


#undef _TK_NEED_IMPLEMENTATION
#endif /* _TK_NEED_IMPLEMENTATION */
/* vi:set ts=8 sw=4: */







>




149
150
151
152
153
154
155
156
157
158
159
160
    rect->xmin += dx;
    rect->xmax += dx;
    rect->ymin += dy;
    rect->ymax += dy;

    return rect;
}


#undef _TK_NEED_IMPLEMENTATION
#endif /* _TK_NEED_IMPLEMENTATION */
/* vi:set ts=8 sw=4: */

Changes to generic/tkRangeList.c.

12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "tkRangeList.h"
#include "tkAlloc.h"

#include <tk.h>
#include <string.h>
#include <assert.h>

#if !(__STDC_VERSION__ >= 199901L)
# define _TK_NEED_IMPLEMENTATION
# include "tkRangeListPriv.h"
#endif

#ifndef MIN
# define MIN(a,b) ((a) < (b) ? a : b)
#endif







|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "tkRangeList.h"
#include "tkAlloc.h"

#include <tk.h>
#include <string.h>
#include <assert.h>

#ifndef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkRangeListPriv.h"
#endif

#ifndef MIN
# define MIN(a,b) ((a) < (b) ? a : b)
#endif
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#define MEM_SIZE(size) ((unsigned) (Tk_Offset(TkRangeList, items) + (size)*sizeof(TkRange)))


DEBUG_ALLOC(unsigned tkRangeListCountNew = 0);
DEBUG_ALLOC(unsigned tkRangeListCountDestroy = 0);


#if !NDEBUG

static int
ComputeRangeSize(
    const TkRangeList *ranges)
{
    unsigned i;
    int count = 0;

    for (i = 0; i < ranges->size; ++i) {
	count += TkRangeSpan(ranges->items + i);
    }

    return count;
}

#endif /* !NDEBUG */


static TkRange *
LowerBound(
    TkRange *first,
    TkRange *last,
    int low)







|

|













|







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#define MEM_SIZE(size) ((unsigned) (Tk_Offset(TkRangeList, items) + (size)*sizeof(TkRange)))


DEBUG_ALLOC(unsigned tkRangeListCountNew = 0);
DEBUG_ALLOC(unsigned tkRangeListCountDestroy = 0);


#ifndef NDEBUG

static unsigned
ComputeRangeSize(
    const TkRangeList *ranges)
{
    unsigned i;
    int count = 0;

    for (i = 0; i < ranges->size; ++i) {
	count += TkRangeSpan(ranges->items + i);
    }

    return count;
}

#endif /* NDEBUG */


static TkRange *
LowerBound(
    TkRange *first,
    TkRange *last,
    int low)
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
    }

    assert(ComputeRangeSize(ranges) == ranges->count);
    return ranges;
}


#if !NDEBUG

void
TkRangeListPrint(
    const TkRangeList *ranges)
{
    unsigned i;

    for (i = 0; i < ranges->size; ++i) {
	printf("{%d,%d} ", ranges->items[i].low, ranges->items[i].high);
    }
    printf("(%d)\n", ranges->count);
}

#endif /* !NDEBUG */


#if __STDC_VERSION__ >= 199901L
/* Additionally we need stand-alone object code. */
#define inline extern
inline int TkRangeSpan(const TkRange *range);
inline bool TkRangeTest(const TkRange *range, int value);
inline int TkRangeListLow(const TkRangeList *ranges);
inline int TkRangeListHigh(const TkRangeList *ranges);
inline unsigned TkRangeListSpan(const TkRangeList *ranges);
inline unsigned TkRangeListCount(const TkRangeList *ranges);
inline unsigned TkRangeListSize(const TkRangeList *ranges);
inline const TkRange *TkRangeListAccess(const TkRangeList *ranges, unsigned index);
inline const TkRange *TkRangeListFirst(const TkRangeList *ranges);
inline const TkRange *TkRangeListNext(const TkRangeList *ranges, const TkRange *item);
inline bool TkRangeListIsEmpty(const TkRangeList *ranges);
inline bool TkRangeListContains(const TkRangeList *ranges, int value);
inline bool TkRangeListContainsRange(const TkRangeList *ranges, int low, int high);
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */







|













|


|

<
|
|
|
|
|
|
|
|
|
|
|
|
|



648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673

674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
    }

    assert(ComputeRangeSize(ranges) == ranges->count);
    return ranges;
}


#ifndef NDEBUG

void
TkRangeListPrint(
    const TkRangeList *ranges)
{
    unsigned i;

    for (i = 0; i < ranges->size; ++i) {
	printf("{%d,%d} ", ranges->items[i].low, ranges->items[i].high);
    }
    printf("(%d)\n", ranges->count);
}

#endif /* NDEBUG */


#ifdef TK_C99_INLINE_SUPPORT
/* Additionally we need stand-alone object code. */

extern int TkRangeSpan(const TkRange *range);
extern bool TkRangeTest(const TkRange *range, int value);
extern int TkRangeListLow(const TkRangeList *ranges);
extern int TkRangeListHigh(const TkRangeList *ranges);
extern unsigned TkRangeListSpan(const TkRangeList *ranges);
extern unsigned TkRangeListCount(const TkRangeList *ranges);
extern unsigned TkRangeListSize(const TkRangeList *ranges);
extern const TkRange *TkRangeListAccess(const TkRangeList *ranges, unsigned index);
extern const TkRange *TkRangeListFirst(const TkRangeList *ranges);
extern const TkRange *TkRangeListNext(const TkRangeList *ranges, const TkRange *item);
extern bool TkRangeListIsEmpty(const TkRangeList *ranges);
extern bool TkRangeListContains(const TkRangeList *ranges, int value);
extern bool TkRangeListContainsRange(const TkRangeList *ranges, int low, int high);
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */

Changes to generic/tkRangeList.h.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

#if defined(__GNUC__) || defined(__clang__)
# define __warn_unused__ __attribute__((warn_unused_result))
#else
# define __warn_unused__
#endif

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


typedef struct TkRange {
    int low;
    int high;
} TkRange;

/*







<
<
<
<
<
<







19
20
21
22
23
24
25






26
27
28
29
30
31
32

#if defined(__GNUC__) || defined(__clang__)
# define __warn_unused__ __attribute__((warn_unused_result))
#else
# define __warn_unused__
#endif








typedef struct TkRange {
    int low;
    int high;
} TkRange;

/*
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
 * the given range (high - low + 1). Adjacent entries (pairs) will be amalgamated
 * automatically.
 *
 * Example: TkRangeListDelete({{5,6} {8,9}}, 1, 5) -> {{1} {3,4}}
 */
TkRangeList *TkRangeListDelete(TkRangeList *ranges, int low, int high);

#if !NDEBUG
void TkRangeListPrint(const TkRangeList *ranges);
#endif


#if __STDC_VERSION__ >= 199901L
# define _TK_NEED_IMPLEMENTATION
# include "tkRangeListPriv.h"
# undef _TK_NEED_IMPLEMENTATION
#endif

#endif /* _TKRANGELIST */
/* vi:set ts=8 sw=4: */







|




|


<

<


184
185
186
187
188
189
190
191
192
193
194
195
196
197
198

199

200
201
 * the given range (high - low + 1). Adjacent entries (pairs) will be amalgamated
 * automatically.
 *
 * Example: TkRangeListDelete({{5,6} {8,9}}, 1, 5) -> {{1} {3,4}}
 */
TkRangeList *TkRangeListDelete(TkRangeList *ranges, int low, int high);

#ifndef NDEBUG
void TkRangeListPrint(const TkRangeList *ranges);
#endif


#ifdef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkRangeListPriv.h"

#endif

#endif /* _TKRANGELIST */
/* vi:set ts=8 sw=4: */

Changes to generic/tkRangeListPriv.h.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34


#ifdef _TK_NEED_IMPLEMENTATION

#include <stddef.h>
#include <assert.h>

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


inline
int
TkRangeSpan(
    const TkRange *range)
{
    assert(range);







<
<
<
<
<
<







15
16
17
18
19
20
21






22
23
24
25
26
27
28


#ifdef _TK_NEED_IMPLEMENTATION

#include <stddef.h>
#include <assert.h>








inline
int
TkRangeSpan(
    const TkRange *range)
{
    assert(range);
160
161
162
163
164
165
166

167
168
169
170
    const TkRange *item)
{
    assert(item);
    assert(ranges);
    assert(ranges->items <= item && item < ranges->items + ranges->size);
    return ++item == ranges->items + ranges->size ? NULL : item;
}


#undef _TK_NEED_IMPLEMENTATION
#endif /* _TK_NEED_IMPLEMENTATION */
/* vi:set ts=8 sw=4: */







>




154
155
156
157
158
159
160
161
162
163
164
165
    const TkRange *item)
{
    assert(item);
    assert(ranges);
    assert(ranges->items <= item && item < ranges->items + ranges->size);
    return ++item == ranges->items + ranges->size ? NULL : item;
}


#undef _TK_NEED_IMPLEMENTATION
#endif /* _TK_NEED_IMPLEMENTATION */
/* vi:set ts=8 sw=4: */

Changes to generic/tkText.c.

21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include "tkTextUndo.h"
#include "tkTextTagSet.h"
#include "tkBitField.h"
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>

#if !(__STDC_VERSION__ >= 199901L)
# define _TK_NEED_IMPLEMENTATION
# include "tkTextPriv.h"
#endif

#ifndef MAX
# define MAX(a,b) ((a) < (b) ? b : a)
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? a : b)
#endif

#if NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Support of tk8.5.







|











|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include "tkTextUndo.h"
#include "tkTextTagSet.h"
#include "tkBitField.h"
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>

#ifndef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkTextPriv.h"
#endif

#ifndef MAX
# define MAX(a,b) ((a) < (b) ? b : a)
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? a : b)
#endif

#ifdef NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Support of tk8.5.
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
 *
 * Side effects:
 *	Calls Tcl_GetString(objPtr) if objPtr->bytes is not yet resolved.
 *
 *--------------------------------------------------------------
 */

static unsigned
GetByteLength(
    Tcl_Obj *objPtr)
{
    assert(objPtr);

    if (!objPtr->bytes) {
	Tcl_GetString(objPtr);







|







756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
 *
 * Side effects:
 *	Calls Tcl_GetString(objPtr) if objPtr->bytes is not yet resolved.
 *
 *--------------------------------------------------------------
 */

static int
GetByteLength(
    Tcl_Obj *objPtr)
{
    assert(objPtr);

    if (!objPtr->bytes) {
	Tcl_GetString(objPtr);
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
		result = TCL_ERROR;
		goto done;
	    }
	}

	for (; i < objc; i += 2) {
	    TkTextIndex index1, index2;
            Tcl_Obj *get;

	    if (!TkTextGetIndexFromObj(interp, textPtr, objv[i], &index1)) {
		if (objPtr) {
		    Tcl_DecrRefCount(objPtr);
		}
		result = TCL_ERROR;
		goto done;







|







2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
		result = TCL_ERROR;
		goto done;
	    }
	}

	for (; i < objc; i += 2) {
	    TkTextIndex index1, index2;
	    Tcl_Obj *get;

	    if (!TkTextGetIndexFromObj(interp, textPtr, objv[i], &index1)) {
		if (objPtr) {
		    Tcl_DecrRefCount(objPtr);
		}
		result = TCL_ERROR;
		goto done;
4258
4259
4260
4261
4262
4263
4264
4265

4266
4267
4268
4269
4270
4271
4272
TkTextParseHyphenRules(
    TkText *textPtr,
    Tcl_Obj *objPtr,
    int *rulesPtr)
{
    int rules = 0;
    Tcl_Obj **argv;
    int argc, i, k;


    assert(rulesPtr);

    if (Tcl_ListObjGetElements(textPtr->interp, objPtr, &argc, &argv) != TCL_OK) {
	return TCL_ERROR;
    }
    for (i = 0; i < argc; ++i) {







|
>







4258
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
TkTextParseHyphenRules(
    TkText *textPtr,
    Tcl_Obj *objPtr,
    int *rulesPtr)
{
    int rules = 0;
    Tcl_Obj **argv;
    int argc, i;
    unsigned k;

    assert(rulesPtr);

    if (Tcl_ListObjGetElements(textPtr->interp, objPtr, &argc, &argv) != TCL_OK) {
	return TCL_ERROR;
    }
    for (i = 0; i < argc; ++i) {
5385
5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399

    int compare = TkTextIndexCompare(indexPtr1, indexPtr2);

    if (compare == 0) {
	return 0;
    }
    if (compare > 0) {
	return -((int)TkTextIndexCount(textPtr, indexPtr2, indexPtr1, type));
    }
    return TkTextIndexCount(textPtr, indexPtr1, indexPtr2, type);
}

/*
 *----------------------------------------------------------------------
 *







|







5386
5387
5388
5389
5390
5391
5392
5393
5394
5395
5396
5397
5398
5399
5400

    int compare = TkTextIndexCompare(indexPtr1, indexPtr2);

    if (compare == 0) {
	return 0;
    }
    if (compare > 0) {
	return -((int) TkTextIndexCount(textPtr, indexPtr2, indexPtr1, type));
    }
    return TkTextIndexCount(textPtr, indexPtr1, indexPtr2, type);
}

/*
 *----------------------------------------------------------------------
 *
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
 */

static void
TextBlinkProc(
    ClientData clientData)	/* Pointer to record describing text. */
{
    TkText *textPtr = clientData;
    int oldFlags = textPtr->flags;

    if (textPtr->state == TK_TEXT_STATE_DISABLED
	    || !(textPtr->flags & HAVE_FOCUS)
	    || textPtr->insertOffTime == 0) {
	if (!(textPtr->flags & HAVE_FOCUS) && textPtr->insertUnfocussed != TK_TEXT_INSERT_NOFOCUS_NONE) {
	    /*
	     * The widget doesn't have the focus yet it is configured to







|







5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
 */

static void
TextBlinkProc(
    ClientData clientData)	/* Pointer to record describing text. */
{
    TkText *textPtr = clientData;
    unsigned oldFlags = textPtr->flags;

    if (textPtr->state == TK_TEXT_STATE_DISABLED
	    || !(textPtr->flags & HAVE_FOCUS)
	    || textPtr->insertOffTime == 0) {
	if (!(textPtr->flags & HAVE_FOCUS) && textPtr->insertUnfocussed != TK_TEXT_INSERT_NOFOCUS_NONE) {
	    /*
	     * The widget doesn't have the focus yet it is configured to
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
		    *destroyed = true;
		    return rc;
		}
		TkTextIndexRebuild(&index1);
	    }

	    if (tagPtr) {
		unsigned i;

		if (Tcl_ListObjGetElements(interp, tagPtr, &numTags, &tagNamePtrs) != TCL_OK) {
		    rc = TCL_ERROR;
		} else if (numTags > 0) {
		    TkTextTag *tagPtr;

		    tagInfoPtr = TkTextTagSetResize(NULL, sharedTextPtr->tagInfoSize);

		    for (i = 0; i < (unsigned)numTags; ++i) {
			tagPtr = TkTextCreateTag(textPtr, Tcl_GetString(tagNamePtrs[i]), NULL);
#if !TK_TEXT_DONT_USE_BITFIELDS
			if (tagPtr->index >= TkTextTagSetSize(tagInfoPtr)) {
			    tagInfoPtr = TkTextTagSetResize(NULL, sharedTextPtr->tagInfoSize);
			}
#endif
			tagInfoPtr = TkTextTagSetAdd(tagInfoPtr, tagPtr->index);







|








|







6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
		    *destroyed = true;
		    return rc;
		}
		TkTextIndexRebuild(&index1);
	    }

	    if (tagPtr) {
		int i;

		if (Tcl_ListObjGetElements(interp, tagPtr, &numTags, &tagNamePtrs) != TCL_OK) {
		    rc = TCL_ERROR;
		} else if (numTags > 0) {
		    TkTextTag *tagPtr;

		    tagInfoPtr = TkTextTagSetResize(NULL, sharedTextPtr->tagInfoSize);

		    for (i = 0; i < numTags; ++i) {
			tagPtr = TkTextCreateTag(textPtr, Tcl_GetString(tagNamePtrs[i]), NULL);
#if !TK_TEXT_DONT_USE_BITFIELDS
			if (tagPtr->index >= TkTextTagSetSize(tagInfoPtr)) {
			    tagInfoPtr = TkTextTagSetResize(NULL, sharedTextPtr->tagInfoSize);
			}
#endif
			tagInfoPtr = TkTextTagSetAdd(tagInfoPtr, tagPtr->index);
6760
6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
6773
6774
	/*
	 * TODO: Use new elide structure, but this requires a redesign of the whole
	 * search algorithm.
	 */

	for ( ; leftToScan >= 0 && segPtr; segPtr = segPtr->nextPtr) {
	    if (segPtr->typePtr == &tkTextCharType) {
		int size = searchSpecPtr->exact ? segPtr->size : CountCharsInSeg(segPtr);

		if (!searchSpecPtr->searchElide && TkTextSegmentIsElided(textPtr, segPtr)) {
		    matchOffset += size;
		} else {
		    leftToScan -= size;
		}
	    } else if (searchSpecPtr->searchHyphens && segPtr->typePtr == &tkTextHyphenType) {







|







6761
6762
6763
6764
6765
6766
6767
6768
6769
6770
6771
6772
6773
6774
6775
	/*
	 * TODO: Use new elide structure, but this requires a redesign of the whole
	 * search algorithm.
	 */

	for ( ; leftToScan >= 0 && segPtr; segPtr = segPtr->nextPtr) {
	    if (segPtr->typePtr == &tkTextCharType) {
		int size = searchSpecPtr->exact ? segPtr->size : (int) CountCharsInSeg(segPtr);

		if (!searchSpecPtr->searchElide && TkTextSegmentIsElided(textPtr, segPtr)) {
		    matchOffset += size;
		} else {
		    leftToScan -= size;
		}
	    } else if (searchSpecPtr->searchHyphens && segPtr->typePtr == &tkTextHyphenType) {
7101
7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115

7116
7117
7118
7119
7120
7121
7122
    };
    enum opts {
	DUMP_ALL, DUMP_TAG_BINDINGS, DUMP_CHARS, DUMP_CMD, DUMP_TAG_CONFIGS, DUMP_DISCARD_SEL,
	DUMP_DISPLAY_CHARS, DUMP_DISPLAY_TEXT, DUMP_DONT_RESOLVE, DUMP_ELIDE, DUMP_IMG,
	DUMP_INSERT_MARK, DUMP_MARK, DUMP_NESTED, DUMP_NODE, DUMP_TEXT_CONFIGS,
	DUMP_TAG, DUMP_TEXT, DUMP_WIN
    };
    static const int dumpFlags[] = {
	0, TK_DUMP_TAG_BINDINGS, TK_DUMP_CHARS, 0, TK_DUMP_TAG_CONFIGS, TK_DUMP_DISCARD_SEL,
	TK_DUMP_DISPLAY_CHARS, TK_DUMP_DISPLAY_TEXT, TK_DUMP_DONT_RESOLVE, TK_DUMP_ELIDE, TK_DUMP_IMG,
	TK_DUMP_INSERT_MARK, TK_DUMP_MARK, TK_DUMP_NESTED, TK_DUMP_NODE, TK_DUMP_TEXT_CONFIGS,
	TK_DUMP_TAG, TK_DUMP_TEXT, TK_DUMP_WIN
    };

    int arg, i;

    unsigned flags = 0;
    const char *myOptStrings[sizeof(optStrings)/sizeof(optStrings[0])];
    int myOptIndices[sizeof(optStrings)/sizeof(optStrings[0])];
    int myOptCount;

    assert(what);
    assert(!index1 == !index2);







|






|
>







7102
7103
7104
7105
7106
7107
7108
7109
7110
7111
7112
7113
7114
7115
7116
7117
7118
7119
7120
7121
7122
7123
7124
    };
    enum opts {
	DUMP_ALL, DUMP_TAG_BINDINGS, DUMP_CHARS, DUMP_CMD, DUMP_TAG_CONFIGS, DUMP_DISCARD_SEL,
	DUMP_DISPLAY_CHARS, DUMP_DISPLAY_TEXT, DUMP_DONT_RESOLVE, DUMP_ELIDE, DUMP_IMG,
	DUMP_INSERT_MARK, DUMP_MARK, DUMP_NESTED, DUMP_NODE, DUMP_TEXT_CONFIGS,
	DUMP_TAG, DUMP_TEXT, DUMP_WIN
    };
    static const unsigned dumpFlags[] = {
	0, TK_DUMP_TAG_BINDINGS, TK_DUMP_CHARS, 0, TK_DUMP_TAG_CONFIGS, TK_DUMP_DISCARD_SEL,
	TK_DUMP_DISPLAY_CHARS, TK_DUMP_DISPLAY_TEXT, TK_DUMP_DONT_RESOLVE, TK_DUMP_ELIDE, TK_DUMP_IMG,
	TK_DUMP_INSERT_MARK, TK_DUMP_MARK, TK_DUMP_NESTED, TK_DUMP_NODE, TK_DUMP_TEXT_CONFIGS,
	TK_DUMP_TAG, TK_DUMP_TEXT, TK_DUMP_WIN
    };

    int arg;
    unsigned i;
    unsigned flags = 0;
    const char *myOptStrings[sizeof(optStrings)/sizeof(optStrings[0])];
    int myOptIndices[sizeof(optStrings)/sizeof(optStrings[0])];
    int myOptCount;

    assert(what);
    assert(!index1 == !index2);
7869
7870
7871
7872
7873
7874
7875
7876
7877
7878
7879
7880
7881
7882
7883
    values[2] = Tcl_NewStringObj(buffer, -1);
    tuple = Tcl_NewListObj(3, values);
    if (!command) {
	Tcl_ListObjAppendList(NULL, Tcl_GetObjResult(interp), tuple);
	Tcl_DecrRefCount(tuple);
	return true;
    } else {
	int oldStateEpoch = TkBTreeEpoch(textPtr->sharedTextPtr->tree);
	Tcl_DString buf;
	int code;

	Tcl_DStringInit(&buf);
	Tcl_DStringAppend(&buf, Tcl_GetString(command), -1);
	Tcl_DStringAppend(&buf, " ", -1);
	Tcl_DStringAppend(&buf, Tcl_GetString(tuple), -1);







|







7871
7872
7873
7874
7875
7876
7877
7878
7879
7880
7881
7882
7883
7884
7885
    values[2] = Tcl_NewStringObj(buffer, -1);
    tuple = Tcl_NewListObj(3, values);
    if (!command) {
	Tcl_ListObjAppendList(NULL, Tcl_GetObjResult(interp), tuple);
	Tcl_DecrRefCount(tuple);
	return true;
    } else {
	unsigned oldStateEpoch = TkBTreeEpoch(textPtr->sharedTextPtr->tree);
	Tcl_DString buf;
	int code;

	Tcl_DStringInit(&buf);
	Tcl_DStringAppend(&buf, Tcl_GetString(command), -1);
	Tcl_DStringAppend(&buf, " ", -1);
	Tcl_DStringAppend(&buf, Tcl_GetString(tuple), -1);
7912
7913
7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
7925
7926

static bool
ObjIsEqual(
    Tcl_Obj *obj1,
    Tcl_Obj *obj2)
{
    char const *b1, *b2;
    unsigned i, length;

    assert(obj1);
    assert(obj2);

    b1 = Tcl_GetString(obj1);
    b2 = Tcl_GetString(obj2);








|







7914
7915
7916
7917
7918
7919
7920
7921
7922
7923
7924
7925
7926
7927
7928

static bool
ObjIsEqual(
    Tcl_Obj *obj1,
    Tcl_Obj *obj2)
{
    char const *b1, *b2;
    int i, length;

    assert(obj1);
    assert(obj2);

    b1 = Tcl_GetString(obj1);
    b2 = Tcl_GetString(obj2);

8511
8512
8513
8514
8515
8516
8517

8518
8519
8520
8521
8522
8523
8524
8525
8526
8527
8528
8529
8530
8531
8532
8533
8534
8535
8536
static void
InspectRetainedUndoItems(
    const TkSharedText *sharedTextPtr,
    Tcl_Obj *objPtr)
{
    if (sharedTextPtr->undoTagListCount > 0 || sharedTextPtr->undoMarkListCount > 0) {
	Tcl_Obj *resultPtr = Tcl_NewObj();

	int i;

	for (i = 0; i < (int)sharedTextPtr->undoTagListCount; ++i) {
	    TkTextInspectUndoTagItem(sharedTextPtr, sharedTextPtr->undoTagList[i], resultPtr);
	}

	for (i = 0; i < (int)sharedTextPtr->undoMarkListCount; ++i) {
	    TkTextInspectUndoMarkItem(sharedTextPtr, &sharedTextPtr->undoMarkList[i], resultPtr);
	}

	Tcl_ListObjLength(NULL, resultPtr, &i);
	if (i == 0) {
	    Tcl_IncrRefCount(resultPtr);
	    Tcl_DecrRefCount(resultPtr);
	} else {
	    Tcl_ListObjAppendElement(NULL, objPtr, resultPtr);
	}
    }
}







>
|

|



|



|
|







8513
8514
8515
8516
8517
8518
8519
8520
8521
8522
8523
8524
8525
8526
8527
8528
8529
8530
8531
8532
8533
8534
8535
8536
8537
8538
8539
static void
InspectRetainedUndoItems(
    const TkSharedText *sharedTextPtr,
    Tcl_Obj *objPtr)
{
    if (sharedTextPtr->undoTagListCount > 0 || sharedTextPtr->undoMarkListCount > 0) {
	Tcl_Obj *resultPtr = Tcl_NewObj();
	unsigned i;
	int len;

	for (i = 0; i < sharedTextPtr->undoTagListCount; ++i) {
	    TkTextInspectUndoTagItem(sharedTextPtr, sharedTextPtr->undoTagList[i], resultPtr);
	}

	for (i = 0; i < sharedTextPtr->undoMarkListCount; ++i) {
	    TkTextInspectUndoMarkItem(sharedTextPtr, &sharedTextPtr->undoMarkList[i], resultPtr);
	}

	Tcl_ListObjLength(NULL, resultPtr, &len);
	if (len == 0) {
	    Tcl_IncrRefCount(resultPtr);
	    Tcl_DecrRefCount(resultPtr);
	} else {
	    Tcl_ListObjAppendElement(NULL, objPtr, resultPtr);
	}
    }
}
8979
8980
8981
8982
8983
8984
8985

8986
8987
8988
8989
8990
8991
8992

    TkSharedText *sharedTextPtr = textPtr->sharedTextPtr;
    TkTextUndoStack st = sharedTextPtr->undoStack;
    Tcl_Obj *var = arrayPtr ? arrayPtr : Tcl_NewStringObj("", 0);
    Tcl_Obj *name[INFO_LAST];
    Tcl_Obj *value[INFO_LAST];
    int usedTags, i;


    name[INFO_UNDOSTACKSIZE ] = Tcl_NewStringObj("undostacksize", -1);
    name[INFO_REDOSTACKSIZE ] = Tcl_NewStringObj("redostacksize", -1);
    name[INFO_UNDODEPTH     ] = Tcl_NewStringObj("undodepth", -1);
    name[INFO_REDODEPTH     ] = Tcl_NewStringObj("redodepth", -1);
    name[INFO_UNDOBYTESIZE  ] = Tcl_NewStringObj("undobytesize", -1);
    name[INFO_REDOBYTESIZE  ] = Tcl_NewStringObj("redobytesize", -1);







>







8982
8983
8984
8985
8986
8987
8988
8989
8990
8991
8992
8993
8994
8995
8996

    TkSharedText *sharedTextPtr = textPtr->sharedTextPtr;
    TkTextUndoStack st = sharedTextPtr->undoStack;
    Tcl_Obj *var = arrayPtr ? arrayPtr : Tcl_NewStringObj("", 0);
    Tcl_Obj *name[INFO_LAST];
    Tcl_Obj *value[INFO_LAST];
    int usedTags, i;
    unsigned k;

    name[INFO_UNDOSTACKSIZE ] = Tcl_NewStringObj("undostacksize", -1);
    name[INFO_REDOSTACKSIZE ] = Tcl_NewStringObj("redostacksize", -1);
    name[INFO_UNDODEPTH     ] = Tcl_NewStringObj("undodepth", -1);
    name[INFO_REDODEPTH     ] = Tcl_NewStringObj("redodepth", -1);
    name[INFO_UNDOBYTESIZE  ] = Tcl_NewStringObj("undobytesize", -1);
    name[INFO_REDOBYTESIZE  ] = Tcl_NewStringObj("redobytesize", -1);
9090
9091
9092
9093
9094
9095
9096
9097
9098
9099
9100
9101
9102
9103
9104
9105
    value[INFO_TAGS          ] = Tcl_NewIntObj(sharedTextPtr->numTags);
    value[INFO_USEDTAGS      ] = Tcl_NewIntObj(usedTags);
    value[INFO_MARKS         ] = Tcl_NewIntObj(sharedTextPtr->numMarks);
    value[INFO_GENERATEDMARKS] = Tcl_NewIntObj(sharedTextPtr->numPrivateMarks);
    value[INFO_LINESPERNODE  ] = Tcl_NewIntObj(TkBTreeLinesPerNode(sharedTextPtr->tree));

    Tcl_UnsetVar(interp, Tcl_GetString(var), 0);
    for (i = 0; i < sizeof(name)/sizeof(name[0]); ++i) {
	Tcl_ObjSetVar2(interp, var, name[i], value[i], 0);
    }

    return var;
}

/*
 *----------------------------------------------------------------------







|
|







9094
9095
9096
9097
9098
9099
9100
9101
9102
9103
9104
9105
9106
9107
9108
9109
    value[INFO_TAGS          ] = Tcl_NewIntObj(sharedTextPtr->numTags);
    value[INFO_USEDTAGS      ] = Tcl_NewIntObj(usedTags);
    value[INFO_MARKS         ] = Tcl_NewIntObj(sharedTextPtr->numMarks);
    value[INFO_GENERATEDMARKS] = Tcl_NewIntObj(sharedTextPtr->numPrivateMarks);
    value[INFO_LINESPERNODE  ] = Tcl_NewIntObj(TkBTreeLinesPerNode(sharedTextPtr->tree));

    Tcl_UnsetVar(interp, Tcl_GetString(var), 0);
    for (k = 0; k < sizeof(name)/sizeof(name[0]); ++k) {
	Tcl_ObjSetVar2(interp, var, name[k], value[k], 0);
    }

    return var;
}

/*
 *----------------------------------------------------------------------
9171
9172
9173
9174
9175
9176
9177
9178

9179
9180
9181
9182
9183
9184
9185
9186
9187
9188
9189
9190
9191
9192
9193
9194
9195
9196
9197
9198
9199
9200
9201
9202
9203
9204
9205
9206
9207
9208
9209
9210
9211
9212
9213
9214
9215
9216
9217
9218
9219
9220
9221
9222
9223
9224
9225
9226
9227
9228
9229
9230
9231
9232
9233
9234
9235
9236
9237
9238
9239
9240
9241
9242
9243
9244
9245
9246
9247
9248
9249
9250
9251
9252
9253
	segPtr = TkTextIndexGetContentSegment(&index, &offset1);
    }

    lastPtr = TkTextIndexGetContentSegment(indexPtr2, &offset2);

    if (segPtr == lastPtr) {
	if (segPtr->typePtr == &tkTextCharType) {
	    Tcl_AppendToObj(resultPtr, segPtr->body.chars + offset1, MIN((int)maxBytes, offset2 - offset1));

	}
    } else {
	TkTextLine *linePtr = segPtr->sectionPtr->linePtr;

	TkTextIndexClear(&index, textPtr);

	if (segPtr->typePtr == &tkTextCharType) {
	    unsigned nbytes = MIN((int)maxBytes, segPtr->size - offset1);
	    Tcl_AppendToObj(resultPtr, segPtr->body.chars + offset1, nbytes);
	    if ((maxBytes -= nbytes) == 0) {
		return resultPtr;
	    }
	} else if (segPtr->typePtr == &tkTextHyphenType) {
	    if (includeHyphens) {
		Tcl_AppendToObj(resultPtr, "\xc2\xad", 2); /* U+002D */
		if ((maxBytes -= MIN(maxBytes, 2)) == 0) {
		    return resultPtr;
		}
	    }
	} else if (segPtr->typePtr == &tkTextBranchType) {
	    if (visibleOnly) {
		TkTextIndexSetSegment(&index, segPtr = segPtr->body.branch.nextPtr);
		if (TkTextIndexRestrictToEndRange(&index) >= 0) {
		    return resultPtr; /* end of text reached */
		}
		linePtr = segPtr->sectionPtr->linePtr;
	    }
	}
	if (!(segPtr = segPtr->nextPtr)) {
	    assert(linePtr->nextPtr);
	    linePtr = linePtr->nextPtr;
	    segPtr = linePtr->segPtr;
	}
	while (segPtr != lastPtr) {
	    if (segPtr->typePtr == &tkTextCharType) {
		unsigned nbytes = MIN((int)maxBytes, segPtr->size);
		Tcl_AppendToObj(resultPtr, segPtr->body.chars, nbytes);
		if ((maxBytes -= nbytes) == 0) {
		    if (lastIndexPtr) {
			TkTextIndexSetSegment(lastIndexPtr, segPtr);
			TkTextIndexAddToByteIndex(lastIndexPtr, nbytes);
		    }
		    return resultPtr; /* end of text reached */
		}
	    } else if (segPtr->typePtr == &tkTextHyphenType) {
		if (includeHyphens) {
		    Tcl_AppendToObj(resultPtr, "\xc2\xad", 2); /* U+002D */
		    if ((maxBytes -= MIN(maxBytes, 2)) == 0) {
			return resultPtr;
		    }
		}
	    } else if (segPtr->typePtr == &tkTextBranchType) {
		if (visibleOnly) {
		    TkTextIndexSetSegment(&index, segPtr = segPtr->body.branch.nextPtr);
		    if (TkTextIndexRestrictToEndRange(&index) >= 0) {
			return resultPtr; /* end of text reached */
		    }
		    linePtr = segPtr->sectionPtr->linePtr;
		}
	    }
	    if (!(segPtr = segPtr->nextPtr)) {
		assert(linePtr->nextPtr);
		linePtr = linePtr->nextPtr;
		segPtr = linePtr->segPtr;
	    }
	}
	if (offset2 > 0) {
	    Tcl_AppendToObj(resultPtr, segPtr->body.chars, MIN((int)maxBytes, offset2));
	}
    }

    return resultPtr;
}

/*







|
>







|







|



















|











|



















|







9175
9176
9177
9178
9179
9180
9181
9182
9183
9184
9185
9186
9187
9188
9189
9190
9191
9192
9193
9194
9195
9196
9197
9198
9199
9200
9201
9202
9203
9204
9205
9206
9207
9208
9209
9210
9211
9212
9213
9214
9215
9216
9217
9218
9219
9220
9221
9222
9223
9224
9225
9226
9227
9228
9229
9230
9231
9232
9233
9234
9235
9236
9237
9238
9239
9240
9241
9242
9243
9244
9245
9246
9247
9248
9249
9250
9251
9252
9253
9254
9255
9256
9257
9258
	segPtr = TkTextIndexGetContentSegment(&index, &offset1);
    }

    lastPtr = TkTextIndexGetContentSegment(indexPtr2, &offset2);

    if (segPtr == lastPtr) {
	if (segPtr->typePtr == &tkTextCharType) {
	    Tcl_AppendToObj(resultPtr, segPtr->body.chars + offset1,
		    MIN(maxBytes, (unsigned) (offset2 - offset1)));
	}
    } else {
	TkTextLine *linePtr = segPtr->sectionPtr->linePtr;

	TkTextIndexClear(&index, textPtr);

	if (segPtr->typePtr == &tkTextCharType) {
	    unsigned nbytes = MIN(maxBytes, (unsigned) segPtr->size - offset1);
	    Tcl_AppendToObj(resultPtr, segPtr->body.chars + offset1, nbytes);
	    if ((maxBytes -= nbytes) == 0) {
		return resultPtr;
	    }
	} else if (segPtr->typePtr == &tkTextHyphenType) {
	    if (includeHyphens) {
		Tcl_AppendToObj(resultPtr, "\xc2\xad", 2); /* U+002D */
		if ((maxBytes -= MIN(maxBytes, 2u)) == 0) {
		    return resultPtr;
		}
	    }
	} else if (segPtr->typePtr == &tkTextBranchType) {
	    if (visibleOnly) {
		TkTextIndexSetSegment(&index, segPtr = segPtr->body.branch.nextPtr);
		if (TkTextIndexRestrictToEndRange(&index) >= 0) {
		    return resultPtr; /* end of text reached */
		}
		linePtr = segPtr->sectionPtr->linePtr;
	    }
	}
	if (!(segPtr = segPtr->nextPtr)) {
	    assert(linePtr->nextPtr);
	    linePtr = linePtr->nextPtr;
	    segPtr = linePtr->segPtr;
	}
	while (segPtr != lastPtr) {
	    if (segPtr->typePtr == &tkTextCharType) {
		unsigned nbytes = MIN(maxBytes, (unsigned) segPtr->size);
		Tcl_AppendToObj(resultPtr, segPtr->body.chars, nbytes);
		if ((maxBytes -= nbytes) == 0) {
		    if (lastIndexPtr) {
			TkTextIndexSetSegment(lastIndexPtr, segPtr);
			TkTextIndexAddToByteIndex(lastIndexPtr, nbytes);
		    }
		    return resultPtr; /* end of text reached */
		}
	    } else if (segPtr->typePtr == &tkTextHyphenType) {
		if (includeHyphens) {
		    Tcl_AppendToObj(resultPtr, "\xc2\xad", 2); /* U+002D */
		    if ((maxBytes -= MIN(maxBytes, 2u)) == 0) {
			return resultPtr;
		    }
		}
	    } else if (segPtr->typePtr == &tkTextBranchType) {
		if (visibleOnly) {
		    TkTextIndexSetSegment(&index, segPtr = segPtr->body.branch.nextPtr);
		    if (TkTextIndexRestrictToEndRange(&index) >= 0) {
			return resultPtr; /* end of text reached */
		    }
		    linePtr = segPtr->sectionPtr->linePtr;
		}
	    }
	    if (!(segPtr = segPtr->nextPtr)) {
		assert(linePtr->nextPtr);
		linePtr = linePtr->nextPtr;
		segPtr = linePtr->segPtr;
	    }
	}
	if (offset2 > 0) {
	    Tcl_AppendToObj(resultPtr, segPtr->body.chars, MIN(maxBytes, (unsigned) offset2));
	}
    }

    return resultPtr;
}

/*
11343
11344
11345
11346
11347
11348
11349
11350
11351
11352
11353
11354
11355
11356
11357
    Tcl_AppendResult(interp, buf, NULL);

    return TCL_OK;
}

#endif /* TCL_MAJOR_VERSION > 8 || TCL_MINOR_VERSION > 5 */

#if !NDEBUG
/*
 *----------------------------------------------------------------------
 *
 * TkpTextInspect --
 *
 *	This function is for debugging only, printing the text content
 *	on stdout.







|







11348
11349
11350
11351
11352
11353
11354
11355
11356
11357
11358
11359
11360
11361
11362
    Tcl_AppendResult(interp, buf, NULL);

    return TCL_OK;
}

#endif /* TCL_MAJOR_VERSION > 8 || TCL_MINOR_VERSION > 5 */

#ifndef NDEBUG
/*
 *----------------------------------------------------------------------
 *
 * TkpTextInspect --
 *
 *	This function is for debugging only, printing the text content
 *	on stdout.
11382
11383
11384
11385
11386
11387
11388
11389
11390
11391
11392
11393
11394
11395
11396
11397
11398
11399
11400
11401
11402
11403
11404
11405
11406
11407
11408
11409
11410
11411
11412
11413
11414
11415
11416
11417
11418
11419
11420
11421
11422
11423
11424
11425
11426
11427
11428
11429
11430
11431
11432
11433
11434
11435
11436
11437
11438
11439
11440
11441
11442
11443
11444
    Tcl_IncrRefCount(objv[3] = Tcl_NewStringObj("-elide", -1));
    Tcl_IncrRefCount(objv[4] = Tcl_NewStringObj("-chars", -1));
    Tcl_IncrRefCount(objv[5] = Tcl_NewStringObj("-image", -1));
    Tcl_IncrRefCount(objv[6] = Tcl_NewStringObj("-window", -1));
    Tcl_IncrRefCount(objv[7] = Tcl_NewStringObj("-mark", -1));
    Tcl_IncrRefCount(objv[8] = Tcl_NewStringObj("-tag", -1));
    TextInspectCmd(textPtr, textPtr->interp, sizeof(objv)/sizeof(objv[0]), objv);
    for (i = 0; i < sizeof(objv)/sizeof(objv[0]); ++i) {
	Tcl_DecrRefCount(objv[i]);
    }
    Tcl_ListObjGetElements(textPtr->interp, Tcl_GetObjResult(textPtr->interp), &argc, &argv);
    for (i = 0; i < argc; ++i) {
	printf("%s\n", Tcl_GetString(argv[i]));
    }
    Tcl_SetObjResult(textPtr->interp, resultPtr);
    Tcl_DecrRefCount(resultPtr);
}

#endif /* !NDEBUG */

/*
 *----------------------------------------------------------------------
 *
 * TkpTextDump --
 *
 *	This function is for debugging only, printing the text content
 *	on stdout.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */
#if !NDEBUG

void
TkpTextDump(
    TkText *textPtr)
{
    Tcl_Obj *resultPtr;
    Tcl_Obj *objv[4];
    Tcl_Obj **argv;
    int argc, i;

    Tcl_IncrRefCount(resultPtr = Tcl_GetObjResult(textPtr->interp));
    Tcl_ResetResult(textPtr->interp);

    Tcl_IncrRefCount(objv[0] = Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1));
    Tcl_IncrRefCount(objv[1] = Tcl_NewStringObj("dump", -1));
    Tcl_IncrRefCount(objv[2] = Tcl_NewStringObj("begin", -1));
    Tcl_IncrRefCount(objv[3] = Tcl_NewStringObj("end", -1));
    TextDumpCmd(textPtr, textPtr->interp, sizeof(objv)/sizeof(objv[0]), objv);
    for (i = 0; i < sizeof(objv)/sizeof(objv[0]); ++i) {
	Tcl_DecrRefCount(objv[i]);
    }

    Tcl_ListObjGetElements(textPtr->interp, Tcl_GetObjResult(textPtr->interp), &argc, &argv);
    for (i = 0; i < argc; i += 3) {
	char const *type = Tcl_GetString(argv[i]);
	char const *text = Tcl_GetString(argv[i + 1]);







|










|

















|


















|







11387
11388
11389
11390
11391
11392
11393
11394
11395
11396
11397
11398
11399
11400
11401
11402
11403
11404
11405
11406
11407
11408
11409
11410
11411
11412
11413
11414
11415
11416
11417
11418
11419
11420
11421
11422
11423
11424
11425
11426
11427
11428
11429
11430
11431
11432
11433
11434
11435
11436
11437
11438
11439
11440
11441
11442
11443
11444
11445
11446
11447
11448
11449
    Tcl_IncrRefCount(objv[3] = Tcl_NewStringObj("-elide", -1));
    Tcl_IncrRefCount(objv[4] = Tcl_NewStringObj("-chars", -1));
    Tcl_IncrRefCount(objv[5] = Tcl_NewStringObj("-image", -1));
    Tcl_IncrRefCount(objv[6] = Tcl_NewStringObj("-window", -1));
    Tcl_IncrRefCount(objv[7] = Tcl_NewStringObj("-mark", -1));
    Tcl_IncrRefCount(objv[8] = Tcl_NewStringObj("-tag", -1));
    TextInspectCmd(textPtr, textPtr->interp, sizeof(objv)/sizeof(objv[0]), objv);
    for (i = 0; i < (int) (sizeof(objv)/sizeof(objv[0])); ++i) {
	Tcl_DecrRefCount(objv[i]);
    }
    Tcl_ListObjGetElements(textPtr->interp, Tcl_GetObjResult(textPtr->interp), &argc, &argv);
    for (i = 0; i < argc; ++i) {
	printf("%s\n", Tcl_GetString(argv[i]));
    }
    Tcl_SetObjResult(textPtr->interp, resultPtr);
    Tcl_DecrRefCount(resultPtr);
}

#endif /* NDEBUG */

/*
 *----------------------------------------------------------------------
 *
 * TkpTextDump --
 *
 *	This function is for debugging only, printing the text content
 *	on stdout.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */
#ifndef NDEBUG

void
TkpTextDump(
    TkText *textPtr)
{
    Tcl_Obj *resultPtr;
    Tcl_Obj *objv[4];
    Tcl_Obj **argv;
    int argc, i;

    Tcl_IncrRefCount(resultPtr = Tcl_GetObjResult(textPtr->interp));
    Tcl_ResetResult(textPtr->interp);

    Tcl_IncrRefCount(objv[0] = Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1));
    Tcl_IncrRefCount(objv[1] = Tcl_NewStringObj("dump", -1));
    Tcl_IncrRefCount(objv[2] = Tcl_NewStringObj("begin", -1));
    Tcl_IncrRefCount(objv[3] = Tcl_NewStringObj("end", -1));
    TextDumpCmd(textPtr, textPtr->interp, sizeof(objv)/sizeof(objv[0]), objv);
    for (i = 0; i < (int) (sizeof(objv)/sizeof(objv[0])); ++i) {
	Tcl_DecrRefCount(objv[i]);
    }

    Tcl_ListObjGetElements(textPtr->interp, Tcl_GetObjResult(textPtr->interp), &argc, &argv);
    for (i = 0; i < argc; i += 3) {
	char const *type = Tcl_GetString(argv[i]);
	char const *text = Tcl_GetString(argv[i + 1]);
11489
11490
11491
11492
11493
11494
11495
11496
11497
11498
11499
11500
11501
11502
11503
11504
11505
11506
11507
11508
11509
11510
11511
11512
11513
11514
11515
11516
11517
11518
11519
11520
11521
11522
11523
11524
11525
11526
11527
11528
11529
11530
11531
11532
11533
11534
11535
11536
11537
11538
11539
11540
11541
11542
11543
11544
11545
11546
11547
11548
	}
    }

    Tcl_SetObjResult(textPtr->interp, resultPtr);
    Tcl_DecrRefCount(resultPtr);
}

#endif /* !NDEBUG */


#if __STDC_VERSION__ >= 199901L
/* Additionally we need stand-alone object code. */
#define inline extern
inline TkSharedText *	TkBTreeGetShared(TkTextBTree tree);
inline int		TkBTreeGetNumberOfDisplayLines(const TkTextPixelInfo *pixelInfo);
inline TkTextPixelInfo *TkBTreeLinePixelInfo(const TkText *textPtr, TkTextLine *linePtr);
inline unsigned		TkBTreeEpoch(TkTextBTree tree);
inline unsigned		TkBTreeIncrEpoch(TkTextBTree tree);
inline struct Node	*TkBTreeGetRoot(TkTextBTree tree);
inline TkTextLine *	TkBTreePrevLogicalLine(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, TkTextLine *linePtr);
inline TkTextTag *	TkBTreeGetTags(const TkTextIndex *indexPtr);
inline TkTextLine *	TkBTreeGetStartLine(const TkText *textPtr);
inline TkTextLine *	TkBTreeGetLastLine(const TkText *textPtr);
inline TkTextLine *	TkBTreeNextLine(const TkText *textPtr, TkTextLine *linePtr);
inline TkTextLine *	TkBTreePrevLine(const TkText *textPtr, TkTextLine *linePtr);
inline unsigned		TkBTreeCountLines(const TkTextBTree tree, const TkTextLine *linePtr1,
			    const TkTextLine *linePtr2);
inline bool		TkTextIsDeadPeer(const TkText *textPtr);
inline bool		TkTextIsStartEndMarker(const TkTextSegment *segPtr);
inline bool		TkTextIsSpecialMark(const TkTextSegment *segPtr);
inline bool		TkTextIsPrivateMark(const TkTextSegment *segPtr);
inline bool		TkTextIsSpecialOrPrivateMark(const TkTextSegment *segPtr);
inline bool		TkTextIsNormalOrSpecialMark(const TkTextSegment *segPtr);
inline bool		TkTextIsNormalMark(const TkTextSegment *segPtr);
inline bool		TkTextIsStableMark(const TkTextSegment *segPtr);
inline void		TkTextIndexSetEpoch(TkTextIndex *indexPtr, unsigned epoch);
inline void		TkTextIndexUpdateEpoch(TkTextIndex *indexPtr, unsigned epoch);
inline void		TkTextIndexSetPeer(TkTextIndex *indexPtr, TkText *textPtr);
inline void		TkTextIndexSetToLastChar2(TkTextIndex *indexPtr, TkTextLine *linePtr);
inline void		TkTextIndexInvalidate(TkTextIndex *indexPtr);
inline TkTextLine *	TkTextIndexGetLine(const TkTextIndex *indexPtr);
inline TkTextSegment *	TkTextIndexGetSegment(const TkTextIndex *indexPtr);
inline TkSharedText *	TkTextIndexGetShared(const TkTextIndex *indexPtr);
inline bool		TkTextIndexSameLines(const TkTextIndex *indexPtr1, const TkTextIndex *indexPtr2);
inline void		TkTextIndexSave(TkTextIndex *indexPtr);
# if TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION < 7 && TCL_UTF_MAX <= 4
inline int		TkUtfToUniChar(const char *src, int *chPtr);
# endif
#endif /* __STDC_VERSION__ >= 199901L */


/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 105
 * End:
 * vi:set ts=8 sw=4:
 */







|


|

<
|
|
|
|
|
|
|

|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|












11494
11495
11496
11497
11498
11499
11500
11501
11502
11503
11504
11505

11506
11507
11508
11509
11510
11511
11512
11513
11514
11515
11516
11517
11518
11519
11520
11521
11522
11523
11524
11525
11526
11527
11528
11529
11530
11531
11532
11533
11534
11535
11536
11537
11538
11539
11540
11541
11542
11543
11544
11545
11546
11547
11548
11549
11550
11551
11552
	}
    }

    Tcl_SetObjResult(textPtr->interp, resultPtr);
    Tcl_DecrRefCount(resultPtr);
}

#endif /* NDEBUG */


#ifdef TK_C99_INLINE_SUPPORT
/* Additionally we need stand-alone object code. */

extern TkSharedText *	TkBTreeGetShared(TkTextBTree tree);
extern int		TkBTreeGetNumberOfDisplayLines(const TkTextPixelInfo *pixelInfo);
extern TkTextPixelInfo *TkBTreeLinePixelInfo(const TkText *textPtr, TkTextLine *linePtr);
extern unsigned		TkBTreeEpoch(TkTextBTree tree);
extern unsigned		TkBTreeIncrEpoch(TkTextBTree tree);
extern struct Node	*TkBTreeGetRoot(TkTextBTree tree);
extern TkTextLine *	TkBTreePrevLogicalLine(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, TkTextLine *linePtr);
extern TkTextTag *	TkBTreeGetTags(const TkTextIndex *indexPtr);
extern TkTextLine *	TkBTreeGetStartLine(const TkText *textPtr);
extern TkTextLine *	TkBTreeGetLastLine(const TkText *textPtr);
extern TkTextLine *	TkBTreeNextLine(const TkText *textPtr, TkTextLine *linePtr);
extern TkTextLine *	TkBTreePrevLine(const TkText *textPtr, TkTextLine *linePtr);
extern unsigned		TkBTreeCountLines(const TkTextBTree tree, const TkTextLine *linePtr1,
			    const TkTextLine *linePtr2);
extern bool		TkTextIsDeadPeer(const TkText *textPtr);
extern bool		TkTextIsStartEndMarker(const TkTextSegment *segPtr);
extern bool		TkTextIsSpecialMark(const TkTextSegment *segPtr);
extern bool		TkTextIsPrivateMark(const TkTextSegment *segPtr);
extern bool		TkTextIsSpecialOrPrivateMark(const TkTextSegment *segPtr);
extern bool		TkTextIsNormalOrSpecialMark(const TkTextSegment *segPtr);
extern bool		TkTextIsNormalMark(const TkTextSegment *segPtr);
extern bool		TkTextIsStableMark(const TkTextSegment *segPtr);
extern void		TkTextIndexSetEpoch(TkTextIndex *indexPtr, unsigned epoch);
extern void		TkTextIndexUpdateEpoch(TkTextIndex *indexPtr, unsigned epoch);
extern void		TkTextIndexSetPeer(TkTextIndex *indexPtr, TkText *textPtr);
extern void		TkTextIndexSetToLastChar2(TkTextIndex *indexPtr, TkTextLine *linePtr);
extern void		TkTextIndexInvalidate(TkTextIndex *indexPtr);
extern TkTextLine *	TkTextIndexGetLine(const TkTextIndex *indexPtr);
extern TkTextSegment *	TkTextIndexGetSegment(const TkTextIndex *indexPtr);
extern TkSharedText *	TkTextIndexGetShared(const TkTextIndex *indexPtr);
extern bool		TkTextIndexSameLines(const TkTextIndex *indexPtr1, const TkTextIndex *indexPtr2);
extern void		TkTextIndexSave(TkTextIndex *indexPtr);
# if TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION < 7 && TCL_UTF_MAX <= 4
extern int		TkUtfToUniChar(const char *src, int *chPtr);
# endif
#endif /* __STDC_VERSION__ >= 199901L */


/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 105
 * End:
 * vi:set ts=8 sw=4:
 */

Changes to generic/tkText.h.

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <stdint.h>

#ifdef MAC_OSX_TK
/* required for TK_LAYOUT_WITH_BASE_CHUNKS */
# include "tkMacOSXInt.h"
#endif

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif

#ifdef BUILD_tk
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLEXPORT
#endif

#if TK_CHECK_ALLOCS
# define DEBUG_ALLOC(expr) expr







<
<
<
<
<
<







29
30
31
32
33
34
35






36
37
38
39
40
41
42
#include <stdint.h>

#ifdef MAC_OSX_TK
/* required for TK_LAYOUT_WITH_BASE_CHUNKS */
# include "tkMacOSXInt.h"
#endif







#ifdef BUILD_tk
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLEXPORT
#endif

#if TK_CHECK_ALLOCS
# define DEBUG_ALLOC(expr) expr
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
    struct TkText *textPtr;
				/* If non-NULL, then this tag only applies to the given text widget
				 * (when there are peer widgets). */
    struct Node *rootPtr;	/* Pointer into the B-Tree at the lowest node that completely
    				 * dominates the ranges of text occupied by the tag. At this node
				 * there is no information about the tag. One or more children of
				 * the node do contain information about the tag. */
    int32_t priority;		/* Priority of this tag within widget. 0 means lowest priority.
    				 * Exactly one tag has each integer value between 0 and numTags-1. */
    uint32_t index;		/* Unique index for fast tag lookup. It is guaranteed that the index
    				 * number is less or equal than 'TkBitSize(sharedTextPtr->usedTags)'.*/
    unsigned refCount;		/* Number of objects referring to us. */
    bool isDisabled;		/* This tag is disabled? */

    /*







|







749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
    struct TkText *textPtr;
				/* If non-NULL, then this tag only applies to the given text widget
				 * (when there are peer widgets). */
    struct Node *rootPtr;	/* Pointer into the B-Tree at the lowest node that completely
    				 * dominates the ranges of text occupied by the tag. At this node
				 * there is no information about the tag. One or more children of
				 * the node do contain information about the tag. */
    uint32_t priority;		/* Priority of this tag within widget. 0 means lowest priority.
    				 * Exactly one tag has each integer value between 0 and numTags-1. */
    uint32_t index;		/* Unique index for fast tag lookup. It is guaranteed that the index
    				 * number is less or equal than 'TkBitSize(sharedTextPtr->usedTags)'.*/
    unsigned refCount;		/* Number of objects referring to us. */
    bool isDisabled;		/* This tag is disabled? */

    /*
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
    TkTextUndoToken *recentTagAddRemoveToken;
    				/* Holds the undo information of last tag add/remove operation. */
    TkTextUndoToken *recentChangePriorityToken;
    				/* Holds the undo information of last tag lower/raise operation. */
    bool recentTagAddRemoveTokenIsNull;
    				/* 'recentTagAddRemoveToken' is null, this means the pointer still
				 * is valid, but should not be saved onto undo stack. */
    int32_t savedPriority; 	/* Contains the priority before recentChangePriorityToken will be set. */
    int32_t undoTagListIndex;	/* Index to entry in 'undoTagList', is -1 if not in 'undoTagList'. */

    /*
     * Information for displaying text with this tag. The information belows
     * acts as an override on information specified by lower-priority tags.
     * If no value is specified, then the next-lower-priority tag on the text
     * determins the value. The text widget itself provides defaults if no tag







|







778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
    TkTextUndoToken *recentTagAddRemoveToken;
    				/* Holds the undo information of last tag add/remove operation. */
    TkTextUndoToken *recentChangePriorityToken;
    				/* Holds the undo information of last tag lower/raise operation. */
    bool recentTagAddRemoveTokenIsNull;
    				/* 'recentTagAddRemoveToken' is null, this means the pointer still
				 * is valid, but should not be saved onto undo stack. */
    uint32_t savedPriority; 	/* Contains the priority before recentChangePriorityToken will be set. */
    int32_t undoTagListIndex;	/* Index to entry in 'undoTagList', is -1 if not in 'undoTagList'. */

    /*
     * Information for displaying text with this tag. The information belows
     * acts as an override on information specified by lower-priority tags.
     * If no value is specified, then the next-lower-priority tag on the text
     * determins the value. The text widget itself provides defaults if no tag
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909

    bool affectsDisplay;	/* True means that this tag affects the way information is
    				 * displayed on the screen (so need to redisplay if tag changes). */
    bool affectsDisplayGeometry;/* True means that this tag affects the size with which
    				 * information is displayed on the screen (so need to recalculate
				 * line dimensions if tag changes). */
    Tk_OptionTable optionTable;	/* Token representing the configuration specifications. */
    } TkTextTag;

/*
 * Some definitions for tag search, used by TkBTreeStartSearch, TkBTreeStartSearchBack:
 */

typedef enum {
    SEARCH_NEXT_TAGON,		/* Search for next range, this will skip the current range. */







|







889
890
891
892
893
894
895
896
897
898
899
900
901
902
903

    bool affectsDisplay;	/* True means that this tag affects the way information is
    				 * displayed on the screen (so need to redisplay if tag changes). */
    bool affectsDisplayGeometry;/* True means that this tag affects the size with which
    				 * information is displayed on the screen (so need to recalculate
				 * line dimensions if tag changes). */
    Tk_OptionTable optionTable;	/* Token representing the configuration specifications. */
} TkTextTag;

/*
 * Some definitions for tag search, used by TkBTreeStartSearch, TkBTreeStartSearchBack:
 */

typedef enum {
    SEARCH_NEXT_TAGON,		/* Search for next range, this will skip the current range. */
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
MODULE_SCOPE int	TkBTreeLoad(TkText *textPtr, Tcl_Obj *content);
MODULE_SCOPE void	TkBTreeDeleteIndexRange(TkSharedText *sharedTextPtr,
			    TkTextIndex *index1Ptr, TkTextIndex *index2Ptr,
			    int flags, TkTextUndoInfo *undoInfo);
inline unsigned		TkBTreeEpoch(TkTextBTree tree);
inline unsigned		TkBTreeIncrEpoch(TkTextBTree tree);
inline struct Node	* TkBTreeGetRoot(TkTextBTree tree);
MODULE_SCOPE TkTextLine * TkBTreeFindLine(TkTextBTree tree, const TkText *textPtr, int line);
MODULE_SCOPE TkTextLine * TkBTreeFindPixelLine(TkTextBTree tree,
			    const TkText *textPtr, int pixels, int32_t *pixelOffset);
MODULE_SCOPE TkTextLine * TkBTreeGetLogicalLine(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, TkTextLine *linePtr);
MODULE_SCOPE TkTextLine * TkBTreeNextLogicalLine(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, TkTextLine *linePtr);
inline TkTextLine *	TkBTreePrevLogicalLine(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, TkTextLine *linePtr);
MODULE_SCOPE TkTextLine * TkBTreeNextDisplayLine(TkText *textPtr, TkTextLine *linePtr,
			    int *displayLineNo, unsigned offset);
MODULE_SCOPE TkTextLine * TkBTreePrevDisplayLine(TkText *textPtr, TkTextLine *linePtr,
			    int *displayLineNo, unsigned offset);
MODULE_SCOPE TkTextSegment * TkBTreeFindStartOfElidedRange(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, const TkTextSegment *segPtr);
MODULE_SCOPE TkTextSegment * TkBTreeFindEndOfElidedRange(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, const TkTextSegment *segPtr);
inline TkTextTag *	TkBTreeGetTags(const TkTextIndex *indexPtr);
MODULE_SCOPE TkTextTag * TkBTreeGetSegmentTags(const TkSharedText *sharedTextPtr,
			    const TkTextSegment *segPtr, const TkText *textPtr);







|









|

|







1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
MODULE_SCOPE int	TkBTreeLoad(TkText *textPtr, Tcl_Obj *content);
MODULE_SCOPE void	TkBTreeDeleteIndexRange(TkSharedText *sharedTextPtr,
			    TkTextIndex *index1Ptr, TkTextIndex *index2Ptr,
			    int flags, TkTextUndoInfo *undoInfo);
inline unsigned		TkBTreeEpoch(TkTextBTree tree);
inline unsigned		TkBTreeIncrEpoch(TkTextBTree tree);
inline struct Node	* TkBTreeGetRoot(TkTextBTree tree);
MODULE_SCOPE TkTextLine * TkBTreeFindLine(TkTextBTree tree, const TkText *textPtr, unsigned line);
MODULE_SCOPE TkTextLine * TkBTreeFindPixelLine(TkTextBTree tree,
			    const TkText *textPtr, int pixels, int32_t *pixelOffset);
MODULE_SCOPE TkTextLine * TkBTreeGetLogicalLine(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, TkTextLine *linePtr);
MODULE_SCOPE TkTextLine * TkBTreeNextLogicalLine(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, TkTextLine *linePtr);
inline TkTextLine *	TkBTreePrevLogicalLine(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, TkTextLine *linePtr);
MODULE_SCOPE TkTextLine * TkBTreeNextDisplayLine(TkText *textPtr, TkTextLine *linePtr,
			    unsigned *displayLineNo, unsigned offset);
MODULE_SCOPE TkTextLine * TkBTreePrevDisplayLine(TkText *textPtr, TkTextLine *linePtr,
			    unsigned *displayLineNo, unsigned offset);
MODULE_SCOPE TkTextSegment * TkBTreeFindStartOfElidedRange(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, const TkTextSegment *segPtr);
MODULE_SCOPE TkTextSegment * TkBTreeFindEndOfElidedRange(const TkSharedText *sharedTextPtr,
			    const TkText *textPtr, const TkTextSegment *segPtr);
inline TkTextTag *	TkBTreeGetTags(const TkTextIndex *indexPtr);
MODULE_SCOPE TkTextTag * TkBTreeGetSegmentTags(const TkSharedText *sharedTextPtr,
			    const TkTextSegment *segPtr, const TkText *textPtr);
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
MODULE_SCOPE bool	TkTextTestTag(const TkTextIndex *indexPtr, const TkTextTag *tagPtr);
inline bool		TkTextIsDeadPeer(const TkText *textPtr);
MODULE_SCOPE void	TkTextGenerateWidgetViewSyncEvent(TkText *textPtr, bool sendImmediately);
MODULE_SCOPE void	TkTextRunAfterSyncCmd(TkText *textPtr);
MODULE_SCOPE void	TkTextInvalidateLineMetrics(TkSharedText *sharedTextPtr, TkText *textPtr,
			    TkTextLine *linePtr, unsigned lineCount, TkTextInvalidateAction action);
MODULE_SCOPE void	TkTextUpdateLineMetrics(TkText *textPtr, unsigned lineNum, unsigned endLine);
MODULE_SCOPE int	TkTextUpdateOneLine(TkText *textPtr, TkTextLine *linePtr, TkTextIndex *indexPtr,
			    unsigned maxDispLines);
MODULE_SCOPE int	TkTextMarkCmd(TkText *textPtr, Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);
MODULE_SCOPE TkTextSegment * TkTextFindMark(const TkText *textPtr, const char *name);
MODULE_SCOPE TkTextSegment * TkTextFreeMarks(TkSharedText *sharedTextPtr, bool retainPrivateMarks);
MODULE_SCOPE bool	TkTextMarkNameToIndex(TkText *textPtr, const char *name, TkTextIndex *indexPtr);
MODULE_SCOPE void	TkTextMarkSegToIndex(TkText *textPtr,
			    TkTextSegment *markPtr, TkTextIndex *indexPtr);







<
<







1903
1904
1905
1906
1907
1908
1909


1910
1911
1912
1913
1914
1915
1916
MODULE_SCOPE bool	TkTextTestTag(const TkTextIndex *indexPtr, const TkTextTag *tagPtr);
inline bool		TkTextIsDeadPeer(const TkText *textPtr);
MODULE_SCOPE void	TkTextGenerateWidgetViewSyncEvent(TkText *textPtr, bool sendImmediately);
MODULE_SCOPE void	TkTextRunAfterSyncCmd(TkText *textPtr);
MODULE_SCOPE void	TkTextInvalidateLineMetrics(TkSharedText *sharedTextPtr, TkText *textPtr,
			    TkTextLine *linePtr, unsigned lineCount, TkTextInvalidateAction action);
MODULE_SCOPE void	TkTextUpdateLineMetrics(TkText *textPtr, unsigned lineNum, unsigned endLine);


MODULE_SCOPE int	TkTextMarkCmd(TkText *textPtr, Tcl_Interp *interp,
			    int objc, Tcl_Obj *const objv[]);
MODULE_SCOPE TkTextSegment * TkTextFindMark(const TkText *textPtr, const char *name);
MODULE_SCOPE TkTextSegment * TkTextFreeMarks(TkSharedText *sharedTextPtr, bool retainPrivateMarks);
MODULE_SCOPE bool	TkTextMarkNameToIndex(TkText *textPtr, const char *name, TkTextIndex *indexPtr);
MODULE_SCOPE void	TkTextMarkSegToIndex(TkText *textPtr,
			    TkTextSegment *markPtr, TkTextIndex *indexPtr);
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLIMPORT

#endif /* TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 5 */

#undef STRUCT

#if __STDC_VERSION__ >= 199901L
# define _TK_NEED_IMPLEMENTATION
# include "tkTextPriv.h"
#endif

#endif /* _TKTEXT */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 105
 * End:
 * vi:set ts=8 sw=4:
 */







|



<









2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101

2102
2103
2104
2105
2106
2107
2108
2109
2110
# undef TCL_STORAGE_CLASS
# define TCL_STORAGE_CLASS DLLIMPORT

#endif /* TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 5 */

#undef STRUCT

#ifdef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkTextPriv.h"
#endif

#endif /* _TKTEXT */
/*
 * Local Variables:
 * mode: c
 * c-basic-offset: 4
 * fill-column: 105
 * End:
 * vi:set ts=8 sw=4:
 */

Changes to generic/tkTextBTree.c.

25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#ifndef MAX
# define MAX(a,b) (((int) a) < ((int) b) ? b : a)
#endif
#ifndef ABS
# define ABS(a)   (a < 0 ? -a : a)
#endif

#if NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Implementation notes:







|







25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#ifndef MAX
# define MAX(a,b) (((int) a) < ((int) b) ? b : a)
#endif
#ifndef ABS
# define ABS(a)   (a < 0 ? -a : a)
#endif

#ifdef NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Implementation notes:
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

/*
 * Upper and lower bounds on how many children a node may have: rebalance when
 * either of these limits is exceeded. MAX_CHILDREN should be twice
 * MIN_CHILDREN, and MIN_CHILDREN must be >= 2.
 */

#define MIN_CHILDREN 16
#define MAX_CHILDREN (2*MIN_CHILDREN)

/*
 * The data structure below defines a node in the B-tree.
 */

typedef struct TkBTreeNodePixelInfo {
    uint32_t pixels;		/* Number of vertical display pixels. */







|
|







64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79

/*
 * Upper and lower bounds on how many children a node may have: rebalance when
 * either of these limits is exceeded. MAX_CHILDREN should be twice
 * MIN_CHILDREN, and MIN_CHILDREN must be >= 2.
 */

#define MIN_CHILDREN 16u
#define MAX_CHILDREN (2u*MIN_CHILDREN)

/*
 * The data structure below defines a node in the B-tree.
 */

typedef struct TkBTreeNodePixelInfo {
    uint32_t pixels;		/* Number of vertical display pixels. */
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
 */

typedef union {
    void *ptr;
    uintptr_t flag;
} __ptr_to_int;

#define POINTER_IS_MARKED(ptr)	(((__ptr_to_int *) &ptr)->flag & (uintptr_t) 1)
#define MARK_POINTER(ptr)	(((__ptr_to_int *) &ptr)->flag |= (uintptr_t) 1)
#define UNMARK_POINTER(ptr)	(((__ptr_to_int *) &ptr)->flag &= ~(uintptr_t) 1)
#define UNMARKED_INT(ptr)	(((__ptr_to_int *) &ptr)->flag & ~(uintptr_t) 1)

DEBUG_ALLOC(extern unsigned tkTextCountNewSegment);
DEBUG_ALLOC(extern unsigned tkTextCountDestroySegment);
DEBUG_ALLOC(extern unsigned tkTextCountNewNode);







|







492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
 */

typedef union {
    void *ptr;
    uintptr_t flag;
} __ptr_to_int;

#define POINTER_IS_MARKED(ptr)	((bool)(((__ptr_to_int *) &ptr)->flag & (uintptr_t) 1))
#define MARK_POINTER(ptr)	(((__ptr_to_int *) &ptr)->flag |= (uintptr_t) 1)
#define UNMARK_POINTER(ptr)	(((__ptr_to_int *) &ptr)->flag &= ~(uintptr_t) 1)
#define UNMARKED_INT(ptr)	(((__ptr_to_int *) &ptr)->flag & ~(uintptr_t) 1)

DEBUG_ALLOC(extern unsigned tkTextCountNewSegment);
DEBUG_ALLOC(extern unsigned tkTextCountDestroySegment);
DEBUG_ALLOC(extern unsigned tkTextCountNewNode);
1438
1439
1440
1441
1442
1443
1444

1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
    }

    /*
     * Increment the line and pixel counts in all the parent nodes of the
     * insertion point, then rebalance the tree if necessary.
     */


    SubtractPixelCount2(treePtr, nodePtr, -((int)changeToLineCount),
	    -((int)changeToLogicalLineCount), -((int)changeToBranchCount),
            -((int)size), changeToPixelInfo);
    linePtr->parentPtr->numChildren += changeToLineCount;

    if (nodePtr->numChildren > MAX_CHILDREN) {
	Rebalance(treePtr, nodePtr);
    }

    /*







>
|
|
|







1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
    }

    /*
     * Increment the line and pixel counts in all the parent nodes of the
     * insertion point, then rebalance the tree if necessary.
     */

	/* MSVC cannot implicitly convert unsigned to signed. */
    SubtractPixelCount2(treePtr, nodePtr, -((int) changeToLineCount),
	    -((int) changeToLogicalLineCount), -((int) changeToBranchCount),
	    -((int) size), changeToPixelInfo);
    linePtr->parentPtr->numChildren += changeToLineCount;

    if (nodePtr->numChildren > MAX_CHILDREN) {
	Rebalance(treePtr, nodePtr);
    }

    /*
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239

	treePtr->clients -= 1;
    } else {
	/*
	 * Clean up pixel data for the given reference.
	 */

	if (pixelReference == (treePtr->numPixelReferences - 1)) {
	    /*
	     * The widget we're removing has the last index, so deletion is easier.
	     */

	    RemovePixelClient(treePtr, treePtr->rootPtr, pixelReference, -1);
	} else {
	    TkText *adjustPtr;

	    RemovePixelClient(treePtr, treePtr->rootPtr, pixelReference, pixelReference);

	    /*
	     * Now we need to adjust the 'pixelReference' of the peer widget
	     * whose storage we've just moved.
	     */

	    adjustPtr = treePtr->sharedTextPtr->peers;
	    while (adjustPtr) {
		if (adjustPtr->pixelReference == treePtr->numPixelReferences - 1) {
		    adjustPtr->pixelReference = pixelReference;
		    break;
		}
		adjustPtr = adjustPtr->next;
	    }
	    assert(adjustPtr);
	}







|

















|







2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240

	treePtr->clients -= 1;
    } else {
	/*
	 * Clean up pixel data for the given reference.
	 */

	if (pixelReference == (int) (treePtr->numPixelReferences - 1)) {
	    /*
	     * The widget we're removing has the last index, so deletion is easier.
	     */

	    RemovePixelClient(treePtr, treePtr->rootPtr, pixelReference, -1);
	} else {
	    TkText *adjustPtr;

	    RemovePixelClient(treePtr, treePtr->rootPtr, pixelReference, pixelReference);

	    /*
	     * Now we need to adjust the 'pixelReference' of the peer widget
	     * whose storage we've just moved.
	     */

	    adjustPtr = treePtr->sharedTextPtr->peers;
	    while (adjustPtr) {
		if (adjustPtr->pixelReference == (int) treePtr->numPixelReferences - 1) {
		    adjustPtr->pixelReference = pixelReference;
		    break;
		}
		adjustPtr = adjustPtr->next;
	    }
	    assert(adjustPtr);
	}
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
TestIfElided(
    const TkTextTag *tagPtr)
{
    int highestPriority = -1;
    bool elide = false;

    for ( ; tagPtr; tagPtr = tagPtr->nextPtr) {
	if (tagPtr->elideString && tagPtr->priority > highestPriority) {
	    elide = tagPtr->elide;
	    highestPriority = tagPtr->priority;
	}
    }

    return elide;
}







|







3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
TestIfElided(
    const TkTextTag *tagPtr)
{
    int highestPriority = -1;
    bool elide = false;

    for ( ; tagPtr; tagPtr = tagPtr->nextPtr) {
	if (tagPtr->elideString && (int) tagPtr->priority > highestPriority) {
	    elide = tagPtr->elide;
	    highestPriority = tagPtr->priority;
	}
    }

    return elide;
}
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
	TkText *textPtr = index.textPtr;

	for (tagPtr = hyphenTagPtr; tagPtr; tagPtr = tagPtr->nextPtr) {
	    if (!TkTextTagSetTest(linePtr->parentPtr->tagonPtr, tagPtr->index)) {
		AddTagToNode(linePtr->parentPtr, tagPtr, true);
	    }
	    if (tagPtr->elideString
		    && tagPtr->priority > highestPriority
		    && (!tagPtr->textPtr || tagPtr->textPtr == textPtr)) {
		highestPriority = (hyphenElideTagPtr = tagPtr)->priority;
	    }
	}
    }

    DEBUG(indexPtr->discardConsistencyCheck = true);







|







4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
	TkText *textPtr = index.textPtr;

	for (tagPtr = hyphenTagPtr; tagPtr; tagPtr = tagPtr->nextPtr) {
	    if (!TkTextTagSetTest(linePtr->parentPtr->tagonPtr, tagPtr->index)) {
		AddTagToNode(linePtr->parentPtr, tagPtr, true);
	    }
	    if (tagPtr->elideString
		    && (int) tagPtr->priority > highestPriority
		    && (!tagPtr->textPtr || tagPtr->textPtr == textPtr)) {
		highestPriority = (hyphenElideTagPtr = tagPtr)->priority;
	    }
	}
    }

    DEBUG(indexPtr->discardConsistencyCheck = true);
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
		prevPtr = SplitSeg(indexPtr, &info);
	    }
	    if (info.offset >= 0) {
		/*
		 * Fill increased/decreased char segment.
		 */
		segPtr = prevPtr;
		assert(segPtr->size >= info.offset + (int)chunkSize);
		memcpy(segPtr->body.chars + info.offset, string, chunkSize);
		segPtr->sectionPtr->size += chunkSize;
		linePtr->size += chunkSize;
		assert(!tagInfoPtr || TkTextTagSetIsEqual(tagInfoPtr, segPtr->tagInfoPtr));
		tagInfoPtr = segPtr->tagInfoPtr;
	    } else {
		/*







|







4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
		prevPtr = SplitSeg(indexPtr, &info);
	    }
	    if (info.offset >= 0) {
		/*
		 * Fill increased/decreased char segment.
		 */
		segPtr = prevPtr;
		assert(segPtr->size >= (int) (info.offset + chunkSize));
		memcpy(segPtr->body.chars + info.offset, string, chunkSize);
		segPtr->sectionPtr->size += chunkSize;
		linePtr->size += chunkSize;
		assert(!tagInfoPtr || TkTextTagSetIsEqual(tagInfoPtr, segPtr->tagInfoPtr));
		tagInfoPtr = segPtr->tagInfoPtr;
	    } else {
		/*
4516
4517
4518
4519
4520
4521
4522

4523
4524
4525
4526
4527
4528
4529
4530
4531
    }

    /*
     * Increment the line and pixel counts in all the parent nodes of the
     * insertion point, then rebalance the tree if necessary.
     */


    SubtractPixelCount2(treePtr, linePtr->parentPtr, -((int)changeToLineCount),
	    -((int)changeToLogicalLineCount), 0, -((int)size), changeToPixelInfo);

    if ((linePtr->parentPtr->numChildren += changeToLineCount) > MAX_CHILDREN) {
	Rebalance(treePtr, linePtr->parentPtr);
    }

    /*
     * This line now needs to have its height recalculated. This has to be done after Rebalance.







>
|
|







4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
    }

    /*
     * Increment the line and pixel counts in all the parent nodes of the
     * insertion point, then rebalance the tree if necessary.
     */

	/* MSVC cannot implicitly convert unsigned to signed. */
    SubtractPixelCount2(treePtr, linePtr->parentPtr, -((int) changeToLineCount),
	    -((int) changeToLogicalLineCount), 0, -((int) size), changeToPixelInfo);

    if ((linePtr->parentPtr->numChildren += changeToLineCount) > MAX_CHILDREN) {
	Rebalance(treePtr, linePtr->parentPtr);
    }

    /*
     * This line now needs to have its height recalculated. This has to be done after Rebalance.
4554
4555
4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
	for ( ; i != TK_TEXT_TAG_SET_NPOS; i = TkTextTagSetFindNext(tagInfoPtr, i)) {
	    TkTextTag *tPtr = sharedTextPtr->tagLookup[i];

	    assert(tPtr);
	    assert(!tPtr->isDisabled);

	    if (tPtr->elideString
		    && tPtr->priority > highestPriority
		    && (!tPtr->textPtr || tPtr->textPtr == textPtr)) {
		highestPriority = (tagPtr = tPtr)->priority;
	    }
	}

	if (tagPtr) {
	    firstSegPtr->protectionFlag = true;







|







4556
4557
4558
4559
4560
4561
4562
4563
4564
4565
4566
4567
4568
4569
4570
	for ( ; i != TK_TEXT_TAG_SET_NPOS; i = TkTextTagSetFindNext(tagInfoPtr, i)) {
	    TkTextTag *tPtr = sharedTextPtr->tagLookup[i];

	    assert(tPtr);
	    assert(!tPtr->isDisabled);

	    if (tPtr->elideString
		    && (int) tPtr->priority > highestPriority
		    && (!tPtr->textPtr || tPtr->textPtr == textPtr)) {
		highestPriority = (tagPtr = tPtr)->priority;
	    }
	}

	if (tagPtr) {
	    firstSegPtr->protectionFlag = true;
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
    sectionPtr = linePtr->segPtr->sectionPtr;

    assert(!sectionPtr || !sectionPtr->prevPtr);
    assert(!linePtr->lastPtr->nextPtr);
    assert(!propagateChangeOfNumBranches
	    || TkBTreeGetRoot(sharedTextPtr->tree)->numBranches >= linePtr->numBranches);

    changeToNumBranches = -(int)linePtr->numBranches;
    linePtr->numBranches = 0;
    linePtr->numLinks = 0;
    linePtr->size = 0;

    for (segPtr = linePtr->segPtr; segPtr; ) {
	if (!sectionPtr) {
	    TkTextSection *newSectionPtr;







|







5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
    sectionPtr = linePtr->segPtr->sectionPtr;

    assert(!sectionPtr || !sectionPtr->prevPtr);
    assert(!linePtr->lastPtr->nextPtr);
    assert(!propagateChangeOfNumBranches
	    || TkBTreeGetRoot(sharedTextPtr->tree)->numBranches >= linePtr->numBranches);

    changeToNumBranches = -((int) linePtr->numBranches);
    linePtr->numBranches = 0;
    linePtr->numLinks = 0;
    linePtr->size = 0;

    for (segPtr = linePtr->segPtr; segPtr; ) {
	if (!sectionPtr) {
	    TkTextSection *newSectionPtr;
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
 */

static void
FreeLine(
    const BTree *treePtr,
    TkTextLine *linePtr)
{
    int i;

    assert(linePtr->parentPtr);
    DEBUG(linePtr->parentPtr = NULL);

    for (i = 0; i < (int)treePtr->numPixelReferences; ++i) {
	TkTextDispLineInfo *dispLineInfo = linePtr->pixelInfo[i].dispLineInfo;

	if (dispLineInfo) {
	    free(dispLineInfo);
	    DEBUG_ALLOC(tkTextCountDestroyDispInfo++);
	}
    }







|




|







5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
5855
5856
5857
5858
5859
 */

static void
FreeLine(
    const BTree *treePtr,
    TkTextLine *linePtr)
{
    unsigned i;

    assert(linePtr->parentPtr);
    DEBUG(linePtr->parentPtr = NULL);

    for (i = 0; i < treePtr->numPixelReferences; ++i) {
	TkTextDispLineInfo *dispLineInfo = linePtr->pixelInfo[i].dispLineInfo;

	if (dispLineInfo) {
	    free(dispLineInfo);
	    DEBUG_ALLOC(tkTextCountDestroyDispInfo++);
	}
    }
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
    TkTextSegment *segPtr,	/* Copy text from this segment. */
    unsigned offset,		/* Copy text starting at this offset. */
    unsigned length,		/* Number of characters to copy. */
    unsigned newSize)		/* Character size of the new segment. */
{
    assert(segPtr);
    assert(segPtr->typePtr == &tkTextCharType);
    assert(segPtr->size >= (int)(offset + length));

    return MakeCharSeg(segPtr->sectionPtr, segPtr->tagInfoPtr, newSize,
	    segPtr->body.chars + offset, length);
}

/*
 *--------------------------------------------------------------







|







5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
5943
5944
5945
5946
    TkTextSegment *segPtr,	/* Copy text from this segment. */
    unsigned offset,		/* Copy text starting at this offset. */
    unsigned length,		/* Number of characters to copy. */
    unsigned newSize)		/* Character size of the new segment. */
{
    assert(segPtr);
    assert(segPtr->typePtr == &tkTextCharType);
    assert(segPtr->size >= (int) (offset + length));

    return MakeCharSeg(segPtr->sectionPtr, segPtr->tagInfoPtr, newSize,
	    segPtr->body.chars + offset, length);
}

/*
 *--------------------------------------------------------------
5964
5965
5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
{
    TkTextSegment *newPtr1, *newPtr2;

    assert(segPtr);
    assert(segPtr->typePtr == &tkTextCharType);
    assert(segPtr->sectionPtr); /* otherwise segment is freed */
    assert(index > 0);
    assert((int)index < segPtr->size);

    newPtr1 = CopyCharSeg(segPtr, 0, index, index);
    newPtr2 = CopyCharSeg(segPtr, index, segPtr->size - index, segPtr->size - index);

    newPtr1->nextPtr = newPtr2;
    newPtr1->prevPtr = segPtr->prevPtr;
    newPtr2->nextPtr = segPtr->nextPtr;







|







5966
5967
5968
5969
5970
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
{
    TkTextSegment *newPtr1, *newPtr2;

    assert(segPtr);
    assert(segPtr->typePtr == &tkTextCharType);
    assert(segPtr->sectionPtr); /* otherwise segment is freed */
    assert(index > 0);
    assert((int) index < segPtr->size);

    newPtr1 = CopyCharSeg(segPtr, 0, index, index);
    newPtr2 = CopyCharSeg(segPtr, index, segPtr->size - index, segPtr->size - index);

    newPtr1->nextPtr = newPtr2;
    newPtr1->prevPtr = segPtr->prevPtr;
    newPtr2->nextPtr = segPtr->nextPtr;
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
    unsigned oldCapacity, newCapacity;

    assert(splitInfo);
    assert(!splitInfo->splitted);
    assert(splitInfo->increase != 0);
    assert(segPtr);
    assert(segPtr->typePtr == &tkTextCharType);
    assert((int)offset <= segPtr->size);
    assert((int)offset < segPtr->size || segPtr->body.chars[segPtr->size - 1] != '\n');

    /*
     * We must not split if the new char content will be appended
     * to the current content (i.e. offset == segPtr->size).
     */

    if (splitInfo->forceSplit && (int)offset < segPtr->size) {
	unsigned newSize, decreasedSize;
	TkTextSegment *newPtr;

	splitInfo->splitted = true;

	if (offset == 0 && segPtr == segPtr->sectionPtr->linePtr->segPtr) {
	    /*







|
|






|







6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
    unsigned oldCapacity, newCapacity;

    assert(splitInfo);
    assert(!splitInfo->splitted);
    assert(splitInfo->increase != 0);
    assert(segPtr);
    assert(segPtr->typePtr == &tkTextCharType);
    assert((int) offset <= segPtr->size);
    assert((int) offset < segPtr->size || segPtr->body.chars[segPtr->size - 1] != '\n');

    /*
     * We must not split if the new char content will be appended
     * to the current content (i.e. offset == segPtr->size).
     */

    if (splitInfo->forceSplit && (int) offset < segPtr->size) {
	unsigned newSize, decreasedSize;
	TkTextSegment *newPtr;

	splitInfo->splitted = true;

	if (offset == 0 && segPtr == segPtr->sectionPtr->linePtr->segPtr) {
	    /*
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
    Node *nodePtr1;
    Node *nodePtr2;
    unsigned numSegments;
    unsigned maxSegments;
    unsigned byteSize;
    unsigned lineDiff;
    bool steadyMarks;
    int lineNo1;
    int lineNo2;

    assert(firstSegPtr);
    assert(lastSegPtr);
    assert(!undoInfo || undoInfo->token);

    assert(!(flags & DELETE_INCLUSIVE)
	    || firstSegPtr->typePtr->group & (SEG_GROUP_MARK|SEG_GROUP_PROTECT));







|
|







6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
    Node *nodePtr1;
    Node *nodePtr2;
    unsigned numSegments;
    unsigned maxSegments;
    unsigned byteSize;
    unsigned lineDiff;
    bool steadyMarks;
    unsigned lineNo1;
    unsigned lineNo2;

    assert(firstSegPtr);
    assert(lastSegPtr);
    assert(!undoInfo || undoInfo->token);

    assert(!(flags & DELETE_INCLUSIVE)
	    || firstSegPtr->typePtr->group & (SEG_GROUP_MARK|SEG_GROUP_PROTECT));
6786
6787
6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
		if (curNodePtr == nodePtr1 || curNodePtr == nodePtr2) {
		    /*
		     * Update only those nodes which will not be deleted,
		     * because DeleteEmptyNode will do a faster update.
		     */
		    SubtractPixelInfo(treePtr, curLinePtr);
		    if (curLinePtr->numBranches) {
			PropagateChangeOfNumBranches(curLinePtr->parentPtr, -(int)curLinePtr->numBranches);
		    }
		}

		if (--curNodePtr->numChildren == 0) {
		    DeleteEmptyNode(treePtr, curNodePtr);
		}
	    }







|







6788
6789
6790
6791
6792
6793
6794
6795
6796
6797
6798
6799
6800
6801
6802
		if (curNodePtr == nodePtr1 || curNodePtr == nodePtr2) {
		    /*
		     * Update only those nodes which will not be deleted,
		     * because DeleteEmptyNode will do a faster update.
		     */
		    SubtractPixelInfo(treePtr, curLinePtr);
		    if (curLinePtr->numBranches) {
			PropagateChangeOfNumBranches(curLinePtr->parentPtr, -(int) curLinePtr->numBranches);
		    }
		}

		if (--curNodePtr->numChildren == 0) {
		    DeleteEmptyNode(treePtr, curNodePtr);
		}
	    }
7330
7331
7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
 *----------------------------------------------------------------------
 */

TkTextLine *
TkBTreeFindLine(
    TkTextBTree tree,		/* B-tree in which to find line. */
    const TkText *textPtr,	/* Relative to this client of the B-tree. */
    int line)			/* Index of desired line. */
{
    BTree *treePtr = (BTree *) tree;
    Node *nodePtr;
    TkTextLine *linePtr;

    assert(tree || textPtr);

    if (!treePtr) {
	tree = textPtr->sharedTextPtr->tree;
	treePtr = (BTree *) tree;
    }

    nodePtr = treePtr->rootPtr;
    if (line < 0 || (int)nodePtr->numLines <= line) {
	return NULL;
    }

    /*
     * Check for any start/end offset for this text widget.
     */

    if (textPtr) {
	line += TkBTreeLinesTo(tree, NULL, TkBTreeGetStartLine(textPtr), NULL);
	if (line >= (int)nodePtr->numLines) {
	    return NULL;
	}
	if (line > (int)TkBTreeLinesTo(tree, NULL, TkBTreeGetLastLine(textPtr), NULL)) {
	    return NULL;
	}
    }

    if (line == 0) {
	return nodePtr->linePtr;
    }
    if (line == nodePtr->numLines - 1) {
	return nodePtr->lastPtr;
    }

    /*
     * Work down through levels of the tree until a node is found at level 0.
     */

    while (nodePtr->level > 0) {
	for (nodePtr = nodePtr->childPtr;
		nodePtr && (int)nodePtr->numLines <= line;
		nodePtr = nodePtr->nextPtr) {
	    line -= nodePtr->numLines;
	}
	assert(nodePtr);
    }

    /*







|













|









|


|

















|







7332
7333
7334
7335
7336
7337
7338
7339
7340
7341
7342
7343
7344
7345
7346
7347
7348
7349
7350
7351
7352
7353
7354
7355
7356
7357
7358
7359
7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384
7385
7386
7387
7388
7389
7390
7391
 *----------------------------------------------------------------------
 */

TkTextLine *
TkBTreeFindLine(
    TkTextBTree tree,		/* B-tree in which to find line. */
    const TkText *textPtr,	/* Relative to this client of the B-tree. */
    unsigned line)		/* Index of desired line. */
{
    BTree *treePtr = (BTree *) tree;
    Node *nodePtr;
    TkTextLine *linePtr;

    assert(tree || textPtr);

    if (!treePtr) {
	tree = textPtr->sharedTextPtr->tree;
	treePtr = (BTree *) tree;
    }

    nodePtr = treePtr->rootPtr;
    if (nodePtr->numLines <= line) {
	return NULL;
    }

    /*
     * Check for any start/end offset for this text widget.
     */

    if (textPtr) {
	line += TkBTreeLinesTo(tree, NULL, TkBTreeGetStartLine(textPtr), NULL);
	if (line >= nodePtr->numLines) {
	    return NULL;
	}
	if (line > TkBTreeLinesTo(tree, NULL, TkBTreeGetLastLine(textPtr), NULL)) {
	    return NULL;
	}
    }

    if (line == 0) {
	return nodePtr->linePtr;
    }
    if (line == nodePtr->numLines - 1) {
	return nodePtr->lastPtr;
    }

    /*
     * Work down through levels of the tree until a node is found at level 0.
     */

    while (nodePtr->level > 0) {
	for (nodePtr = nodePtr->childPtr;
		nodePtr && nodePtr->numLines <= line;
		nodePtr = nodePtr->nextPtr) {
	    line -= nodePtr->numLines;
	}
	assert(nodePtr);
    }

    /*
9149
9150
9151
9152
9153
9154
9155
9156
9157
9158
9159
9160
9161
9162
9163
    }

    if (!(flags & HAS_TAGON)) {
	flags &= ~HAS_TAGOFF;
    } else if (nchilds < nodePtr->numChildren) {
	flags |= HAS_TAGOFF;
    }
    if (nchilds > (unsigned)(nodePtr->level > 0 ? 1 : 0)) {
	tagPtr->rootPtr = nodePtr;
    }

    nodePtr->tagonPtr = TagSetAddOrErase(nodePtr->tagonPtr, tagPtr, !!(flags & HAS_TAGON));
    nodePtr->tagoffPtr = TagSetAddOrErase(nodePtr->tagoffPtr, tagPtr, !!(flags & HAS_TAGOFF));

    return flags;







|







9151
9152
9153
9154
9155
9156
9157
9158
9159
9160
9161
9162
9163
9164
9165
    }

    if (!(flags & HAS_TAGON)) {
	flags &= ~HAS_TAGOFF;
    } else if (nchilds < nodePtr->numChildren) {
	flags |= HAS_TAGOFF;
    }
    if (nchilds > (nodePtr->level > 0 ? 1u : 0u)) {
	tagPtr->rootPtr = nodePtr;
    }

    nodePtr->tagonPtr = TagSetAddOrErase(nodePtr->tagonPtr, tagPtr, !!(flags & HAS_TAGON));
    nodePtr->tagoffPtr = TagSetAddOrErase(nodePtr->tagoffPtr, tagPtr, !!(flags & HAS_TAGOFF));

    return flags;
10169
10170
10171
10172
10173
10174
10175
10176
10177
10178
10179
10180
10181
10182
10183
		bool affectsDisplayGeometry = TestIfDisplayGeometryIsAffected(sharedTextPtr,
			affectedTagInfoPtr, discardSelection);
		changedProc(sharedTextPtr, textPtr, &startIndex, &endIndex,
			NULL, affectsDisplayGeometry);
	    }
	} else {
	    TkTextSegment *firstPtr, *lastPtr;
	    int lineNo1, lineNo2;

	    if (undoInfo) {
		undoToken = malloc(sizeof(UndoTokenTagClear));
		undoInfo->token = (TkTextUndoToken *) undoToken;
		undoInfo->byteSize = 0;
		undoToken->undoType = &undoTokenClearTagsType;
		undoToken->changeList = NULL;







|







10171
10172
10173
10174
10175
10176
10177
10178
10179
10180
10181
10182
10183
10184
10185
		bool affectsDisplayGeometry = TestIfDisplayGeometryIsAffected(sharedTextPtr,
			affectedTagInfoPtr, discardSelection);
		changedProc(sharedTextPtr, textPtr, &startIndex, &endIndex,
			NULL, affectsDisplayGeometry);
	    }
	} else {
	    TkTextSegment *firstPtr, *lastPtr;
	    unsigned lineNo1, lineNo2;

	    if (undoInfo) {
		undoToken = malloc(sizeof(UndoTokenTagClear));
		undoInfo->token = (TkTextUndoToken *) undoToken;
		undoInfo->byteSize = 0;
		undoToken->undoType = &undoTokenClearTagsType;
		undoToken->changeList = NULL;
12277
12278
12279
12280
12281
12282
12283
12284
12285
12286
12287
12288
12289
12290
12291

	for ( ; i != TK_TEXT_TAG_SET_NPOS; i = TkTextTagSetFindNext(tagInfoPtr, i)) {
	    const TkTextTag *tagPtr = sharedTextPtr->tagLookup[i];

	    assert(tagPtr);
	    assert(!tagPtr->isDisabled);

	    if (tagPtr->lang[0] && tagPtr->priority > highestPriority) {
		langPtr = tagPtr->lang;
		highestPriority = tagPtr->priority;
	    }
	}
    }

    return langPtr;







|







12279
12280
12281
12282
12283
12284
12285
12286
12287
12288
12289
12290
12291
12292
12293

	for ( ; i != TK_TEXT_TAG_SET_NPOS; i = TkTextTagSetFindNext(tagInfoPtr, i)) {
	    const TkTextTag *tagPtr = sharedTextPtr->tagLookup[i];

	    assert(tagPtr);
	    assert(!tagPtr->isDisabled);

	    if (tagPtr->lang[0] && (int) tagPtr->priority > highestPriority) {
		langPtr = tagPtr->lang;
		highestPriority = tagPtr->priority;
	    }
	}
    }

    return langPtr;
12614
12615
12616
12617
12618
12619
12620
12621
12622
12623
12624
12625
12626
12627
12628
12629
12630
12631
12632
12633
12634
12635
12636
12637
12638
12639
12640
12641
12642
    const Node *rootPtr,	/* The root node. */
    const Node *nodePtr,	/* Node whose subtree should be checked. */
    unsigned references)	/* Number of referring widgets which have pixel counts. */
{
    const Node *childNodePtr;
    const TkTextLine *linePtr;
    const TkTextLine *prevLinePtr;
    int numChildren, numLines, numLogicalLines, numBranches;
    int minChildren, size, i;
    NodePixelInfo *pixelInfo = NULL;
    NodePixelInfo pixelInfoBuf[PIXEL_CLIENTS];
    TkTextTagSet *tagonPtr = NULL;
    TkTextTagSet *tagoffPtr = NULL;
    TkTextTagSet *additionalTagoffPtr = NULL;
    unsigned memsize;

    if (nodePtr->level == 0 && !nodePtr->linePtr) {
	Tcl_Panic("CheckNodeConsistency: this node is freed");
    }

    minChildren = nodePtr->parentPtr ? MIN_CHILDREN : (nodePtr->level > 0 ? 2 : 1);
    if ((int)nodePtr->numChildren < minChildren || (int)nodePtr->numChildren > MAX_CHILDREN) {
	Tcl_Panic("CheckNodeConsistency: bad child count (%d)", nodePtr->numChildren);
    }

    if (!nodePtr->linePtr) {
	Tcl_Panic("CheckNodeConsistency: first pointer is NULL");
    }
    if (!nodePtr->lastPtr) {







|
<












|







12616
12617
12618
12619
12620
12621
12622
12623

12624
12625
12626
12627
12628
12629
12630
12631
12632
12633
12634
12635
12636
12637
12638
12639
12640
12641
12642
12643
    const Node *rootPtr,	/* The root node. */
    const Node *nodePtr,	/* Node whose subtree should be checked. */
    unsigned references)	/* Number of referring widgets which have pixel counts. */
{
    const Node *childNodePtr;
    const TkTextLine *linePtr;
    const TkTextLine *prevLinePtr;
    unsigned numLines, numLogicalLines, numBranches, numChildren, minChildren, size, i;

    NodePixelInfo *pixelInfo = NULL;
    NodePixelInfo pixelInfoBuf[PIXEL_CLIENTS];
    TkTextTagSet *tagonPtr = NULL;
    TkTextTagSet *tagoffPtr = NULL;
    TkTextTagSet *additionalTagoffPtr = NULL;
    unsigned memsize;

    if (nodePtr->level == 0 && !nodePtr->linePtr) {
	Tcl_Panic("CheckNodeConsistency: this node is freed");
    }

    minChildren = nodePtr->parentPtr ? MIN_CHILDREN : (nodePtr->level > 0 ? 2 : 1);
    if (nodePtr->numChildren < minChildren || nodePtr->numChildren > MAX_CHILDREN) {
	Tcl_Panic("CheckNodeConsistency: bad child count (%d)", nodePtr->numChildren);
    }

    if (!nodePtr->linePtr) {
	Tcl_Panic("CheckNodeConsistency: first pointer is NULL");
    }
    if (!nodePtr->lastPtr) {
12685
12686
12687
12688
12689
12690
12691
12692
12693
12694
12695
12696
12697
12698
12699
12700
12701
12702
12703
12704
12705
12706
12707
12708
12709
12710
    TkTextTagSetIncrRefCount(tagoffPtr = sharedTextPtr->emptyTagInfoPtr);
    additionalTagoffPtr = NULL;

    if (nodePtr->level == 0) {
	prevLinePtr = NULL;
	linePtr = nodePtr->linePtr;
	for (linePtr = nodePtr->linePtr;
		numChildren < (int)nodePtr->numChildren;
		++numChildren, ++numLines, linePtr = linePtr->nextPtr) {
	    if (!linePtr) {
		Tcl_Panic("CheckNodeConsistency: unexpected end of line chain");
	    }
	    if (linePtr->parentPtr != nodePtr) {
		Tcl_Panic("CheckNodeConsistency: line has wrong parent pointer");
	    }
	    CheckSegments(sharedTextPtr, linePtr);
	    CheckSegmentItems(sharedTextPtr, linePtr);
	    CheckSections(linePtr);
	    for (i = 0; i < (int)references; ++i) {
		pixelInfo[i].pixels += linePtr->pixelInfo[i].height;
		pixelInfo[i].numDispLines += GetDisplayLines(linePtr, i);
	    }
	    if (tagonPtr) {
		tagonPtr = TkTextTagSetJoin(tagonPtr, linePtr->tagonPtr);
		tagoffPtr = TkTextTagSetJoin(tagoffPtr, linePtr->tagoffPtr);
		if (additionalTagoffPtr) {







|










|







12686
12687
12688
12689
12690
12691
12692
12693
12694
12695
12696
12697
12698
12699
12700
12701
12702
12703
12704
12705
12706
12707
12708
12709
12710
12711
    TkTextTagSetIncrRefCount(tagoffPtr = sharedTextPtr->emptyTagInfoPtr);
    additionalTagoffPtr = NULL;

    if (nodePtr->level == 0) {
	prevLinePtr = NULL;
	linePtr = nodePtr->linePtr;
	for (linePtr = nodePtr->linePtr;
		numChildren < nodePtr->numChildren;
		++numChildren, ++numLines, linePtr = linePtr->nextPtr) {
	    if (!linePtr) {
		Tcl_Panic("CheckNodeConsistency: unexpected end of line chain");
	    }
	    if (linePtr->parentPtr != nodePtr) {
		Tcl_Panic("CheckNodeConsistency: line has wrong parent pointer");
	    }
	    CheckSegments(sharedTextPtr, linePtr);
	    CheckSegmentItems(sharedTextPtr, linePtr);
	    CheckSections(linePtr);
	    for (i = 0; i < references; ++i) {
		pixelInfo[i].pixels += linePtr->pixelInfo[i].height;
		pixelInfo[i].numDispLines += GetDisplayLines(linePtr, i);
	    }
	    if (tagonPtr) {
		tagonPtr = TkTextTagSetJoin(tagonPtr, linePtr->tagonPtr);
		tagoffPtr = TkTextTagSetJoin(tagoffPtr, linePtr->tagoffPtr);
		if (additionalTagoffPtr) {
12755
12756
12757
12758
12759
12760
12761
12762
12763
12764
12765
12766
12767
12768
12769
		tagoffPtr = TkTextTagSetJoin(tagoffPtr, nodePtr->tagoffPtr);
		if (additionalTagoffPtr) {
		    additionalTagoffPtr = TkTextTagSetIntersect(additionalTagoffPtr, nodePtr->tagonPtr);
		} else {
		    TkTextTagSetIncrRefCount(additionalTagoffPtr = nodePtr->tagonPtr);
		}
	    }
	    for (i = 0; i < (int)references; i++) {
		pixelInfo[i].pixels += childNodePtr->pixelInfo[i].pixels;
		pixelInfo[i].numDispLines += childNodePtr->pixelInfo[i].numDispLines;
	    }
	}
    }
    if (size != nodePtr->size) {
	Tcl_Panic("CheckNodeConsistency: sum of size (%d) at level %d is wrong (%d is expected)",







|







12756
12757
12758
12759
12760
12761
12762
12763
12764
12765
12766
12767
12768
12769
12770
		tagoffPtr = TkTextTagSetJoin(tagoffPtr, nodePtr->tagoffPtr);
		if (additionalTagoffPtr) {
		    additionalTagoffPtr = TkTextTagSetIntersect(additionalTagoffPtr, nodePtr->tagonPtr);
		} else {
		    TkTextTagSetIncrRefCount(additionalTagoffPtr = nodePtr->tagonPtr);
		}
	    }
	    for (i = 0; i < references; i++) {
		pixelInfo[i].pixels += childNodePtr->pixelInfo[i].pixels;
		pixelInfo[i].numDispLines += childNodePtr->pixelInfo[i].numDispLines;
	    }
	}
    }
    if (size != nodePtr->size) {
	Tcl_Panic("CheckNodeConsistency: sum of size (%d) at level %d is wrong (%d is expected)",
12806
12807
12808
12809
12810
12811
12812
12813
12814
12815
12816
12817
12818
12819
12820
	    }
	}

	TkTextTagSetDecrRefCount(tagonPtr);
	TkTextTagSetDecrRefCount(tagoffPtr);
	TkTextTagSetDecrRefCount(additionalTagoffPtr);
    }
    for (i = 0; i < (int)references; i++) {
	if (pixelInfo[i].pixels != nodePtr->pixelInfo[i].pixels) {
	    Tcl_Panic("CheckNodeConsistency: mismatch in pixel count "
		    "(expected: %d, counted: %d) for widget (%d) at level %d",
		    pixelInfo[i].pixels, nodePtr->pixelInfo[i].pixels, i, nodePtr->level);
	}
	if (pixelInfo[i].numDispLines != nodePtr->pixelInfo[i].numDispLines) {
	    Tcl_Panic("CheckNodeConsistency: mismatch in number of display lines "







|







12807
12808
12809
12810
12811
12812
12813
12814
12815
12816
12817
12818
12819
12820
12821
	    }
	}

	TkTextTagSetDecrRefCount(tagonPtr);
	TkTextTagSetDecrRefCount(tagoffPtr);
	TkTextTagSetDecrRefCount(additionalTagoffPtr);
    }
    for (i = 0; i < references; i++) {
	if (pixelInfo[i].pixels != nodePtr->pixelInfo[i].pixels) {
	    Tcl_Panic("CheckNodeConsistency: mismatch in pixel count "
		    "(expected: %d, counted: %d) for widget (%d) at level %d",
		    pixelInfo[i].pixels, nodePtr->pixelInfo[i].pixels, i, nodePtr->level);
	}
	if (pixelInfo[i].numDispLines != nodePtr->pixelInfo[i].numDispLines) {
	    Tcl_Panic("CheckNodeConsistency: mismatch in number of display lines "
13841
13842
13843
13844
13845
13846
13847
13848
13849
13850
13851
13852
13853
13854
13855
13856
13857
13858
13859
13860
13861
13862
13863
13864
13865
13866
13867
13868
13869
13870
13871
13872
13873
13874
13875
13876
13877
13878
13879
13880
13881
13882
 *
 *----------------------------------------------------------------------
 */

static TkTextLine *
GetLastDisplayLine(
    TkText *textPtr,
    int *displayLineNo)
{
    TkTextLine *linePtr;

    linePtr = textPtr->endMarker->sectionPtr->linePtr;
    linePtr = TkBTreeGetLogicalLine(textPtr->sharedTextPtr, textPtr, linePtr);
    *displayLineNo = GetDisplayLines(linePtr, textPtr->pixelReference);
    return linePtr;
}

TkTextLine *
TkBTreeNextDisplayLine(
    TkText *textPtr,		/* Information about text widget. */
    TkTextLine *linePtr,	/* Start at this logical line. */
    int *displayLineNo,		/* IN: Start at this display line number in given logical line.
    				 * OUT: Store display line number of requested display line. */
    unsigned offset)		/* Offset to requested display line. */
{
    const Node *nodePtr;
    const Node *parentPtr;
    int lineNo, numLines;
    unsigned numDispLines;
    unsigned ref;

    assert(textPtr);
    assert(linePtr->logicalLine || linePtr == TkBTreeGetStartLine(textPtr));
    assert(*displayLineNo >= 0);
    assert(*displayLineNo < (int)GetDisplayLines(linePtr, textPtr->pixelReference));

    if (offset == 0) {
	return linePtr;
    }

    ref = textPtr->pixelReference;
    nodePtr = linePtr->parentPtr;







|













|












|







13842
13843
13844
13845
13846
13847
13848
13849
13850
13851
13852
13853
13854
13855
13856
13857
13858
13859
13860
13861
13862
13863
13864
13865
13866
13867
13868
13869
13870
13871
13872
13873
13874
13875
13876
13877
13878
13879
13880
13881
13882
13883
 *
 *----------------------------------------------------------------------
 */

static TkTextLine *
GetLastDisplayLine(
    TkText *textPtr,
    unsigned *displayLineNo)
{
    TkTextLine *linePtr;

    linePtr = textPtr->endMarker->sectionPtr->linePtr;
    linePtr = TkBTreeGetLogicalLine(textPtr->sharedTextPtr, textPtr, linePtr);
    *displayLineNo = GetDisplayLines(linePtr, textPtr->pixelReference);
    return linePtr;
}

TkTextLine *
TkBTreeNextDisplayLine(
    TkText *textPtr,		/* Information about text widget. */
    TkTextLine *linePtr,	/* Start at this logical line. */
    unsigned *displayLineNo,	/* IN: Start at this display line number in given logical line.
    				 * OUT: Store display line number of requested display line. */
    unsigned offset)		/* Offset to requested display line. */
{
    const Node *nodePtr;
    const Node *parentPtr;
    int lineNo, numLines;
    unsigned numDispLines;
    unsigned ref;

    assert(textPtr);
    assert(linePtr->logicalLine || linePtr == TkBTreeGetStartLine(textPtr));
    assert(*displayLineNo >= 0);
    assert(*displayLineNo < GetDisplayLines(linePtr, textPtr->pixelReference));

    if (offset == 0) {
	return linePtr;
    }

    ref = textPtr->pixelReference;
    nodePtr = linePtr->parentPtr;
13977
13978
13979
13980
13981
13982
13983
13984
13985
13986
13987
13988
13989
13990
13991
13992
13993
13994
13995
13996
13997
13998
13999
14000
14001
14002
14003
14004
14005
14006
14007
14008
14009
14010
14011
14012
14013
14014
14015
14016
14017
 *
 *----------------------------------------------------------------------
 */

static TkTextLine *
GetFirstDisplayLine(
    TkText *textPtr,
    int *displayLineNo)
{
    *displayLineNo = 0;
    return textPtr->startMarker->sectionPtr->linePtr;
}

TkTextLine *
TkBTreePrevDisplayLine(
    TkText *textPtr,		/* Information about text widget. */
    TkTextLine *linePtr,	/* Start at this logical line. */
    int *displayLineNo,		/* IN: Start at this display line number in given logical line.
    				 * OUT: Store display line number of requested display line. */
    unsigned offset)		/* Offset to requested display line. */
{
    const Node *nodeStack[MAX_CHILDREN];
    const Node *nodePtr;
    const Node *parentPtr;
    const Node *nPtr;
    unsigned numDispLines;
    unsigned ref;
    unsigned idx;
    int lineNo;

    assert(textPtr);
    assert(linePtr->logicalLine || linePtr == TkBTreeGetStartLine(textPtr));
    assert(*displayLineNo >= 0);
    assert(*displayLineNo < (int)GetDisplayLines(linePtr, textPtr->pixelReference));

    if (offset == 0) {
	return linePtr;
    }

    ref = textPtr->pixelReference;
    nodePtr = linePtr->parentPtr;







|









|















|







13978
13979
13980
13981
13982
13983
13984
13985
13986
13987
13988
13989
13990
13991
13992
13993
13994
13995
13996
13997
13998
13999
14000
14001
14002
14003
14004
14005
14006
14007
14008
14009
14010
14011
14012
14013
14014
14015
14016
14017
14018
 *
 *----------------------------------------------------------------------
 */

static TkTextLine *
GetFirstDisplayLine(
    TkText *textPtr,
    unsigned *displayLineNo)
{
    *displayLineNo = 0;
    return textPtr->startMarker->sectionPtr->linePtr;
}

TkTextLine *
TkBTreePrevDisplayLine(
    TkText *textPtr,		/* Information about text widget. */
    TkTextLine *linePtr,	/* Start at this logical line. */
    unsigned *displayLineNo,	/* IN: Start at this display line number in given logical line.
    				 * OUT: Store display line number of requested display line. */
    unsigned offset)		/* Offset to requested display line. */
{
    const Node *nodeStack[MAX_CHILDREN];
    const Node *nodePtr;
    const Node *parentPtr;
    const Node *nPtr;
    unsigned numDispLines;
    unsigned ref;
    unsigned idx;
    int lineNo;

    assert(textPtr);
    assert(linePtr->logicalLine || linePtr == TkBTreeGetStartLine(textPtr));
    assert(*displayLineNo >= 0);
    assert(*displayLineNo < GetDisplayLines(linePtr, textPtr->pixelReference));

    if (offset == 0) {
	return linePtr;
    }

    ref = textPtr->pixelReference;
    nodePtr = linePtr->parentPtr;
14525
14526
14527
14528
14529
14530
14531
14532
14533
14534
14535
14536
14537
14538
14539
14540
14541
14542
14543
14544
14545
14546
    }

    if (textPtr) {
	const TkSharedText *sharedTextPtr = treePtr->sharedTextPtr;

	if (textPtr->startMarker != sharedTextPtr->startMarker) {
	    if (linePtr1 == textPtr->startMarker->sectionPtr->linePtr) {
		assert(TkTextSegToIndex(textPtr->startMarker) <= (int)numBytes);
		numBytes -= TkTextSegToIndex(textPtr->startMarker);
	    }
	}
	if (textPtr->endMarker != sharedTextPtr->endMarker) {
	    if (!SegIsAtStartOfLine(textPtr->endMarker)) {
		const TkTextLine *linePtr = textPtr->endMarker->sectionPtr->linePtr;
		assert(linePtr->size - TkTextSegToIndex(textPtr->endMarker) - 1 <= (int)numBytes);
		numBytes -= linePtr->size - TkTextSegToIndex(textPtr->endMarker) - 1;
	    }
	}
    }

    return numBytes;
}







|






|







14526
14527
14528
14529
14530
14531
14532
14533
14534
14535
14536
14537
14538
14539
14540
14541
14542
14543
14544
14545
14546
14547
    }

    if (textPtr) {
	const TkSharedText *sharedTextPtr = treePtr->sharedTextPtr;

	if (textPtr->startMarker != sharedTextPtr->startMarker) {
	    if (linePtr1 == textPtr->startMarker->sectionPtr->linePtr) {
		assert(TkTextSegToIndex(textPtr->startMarker) <= (int) numBytes);
		numBytes -= TkTextSegToIndex(textPtr->startMarker);
	    }
	}
	if (textPtr->endMarker != sharedTextPtr->endMarker) {
	    if (!SegIsAtStartOfLine(textPtr->endMarker)) {
		const TkTextLine *linePtr = textPtr->endMarker->sectionPtr->linePtr;
		assert(linePtr->size - TkTextSegToIndex(textPtr->endMarker) - 1 <= (int) numBytes);
		numBytes -= linePtr->size - TkTextSegToIndex(textPtr->endMarker) - 1;
	    }
	}
    }

    return numBytes;
}
14612
14613
14614
14615
14616
14617
14618
14619
14620
14621
14622
14623
14624
14625
14626
14627
14628
14629
14630
14631

    /*
     * We couldn't find a line, so search inside B-Tree for next level-0
     * node which contains the byte offset.
     */

    while (parentPtr) {
	if (!nodePtr || (!HasLeftNode(nodePtr) && byteIndex >= (int)parentPtr->size)) {
	    nodePtr = parentPtr->nextPtr;
	    parentPtr = parentPtr->parentPtr;
	} else {
	    while (nodePtr) {
		if (byteIndex < (int)nodePtr->size) {
		    if (nodePtr->level > 0) {
			nodePtr = nodePtr->childPtr;
			continue;
		    }
		    /*
		     * We've found the right node, now search for the line.
		     */







|




|







14613
14614
14615
14616
14617
14618
14619
14620
14621
14622
14623
14624
14625
14626
14627
14628
14629
14630
14631
14632

    /*
     * We couldn't find a line, so search inside B-Tree for next level-0
     * node which contains the byte offset.
     */

    while (parentPtr) {
	if (!nodePtr || (!HasLeftNode(nodePtr) && byteIndex >= (int) parentPtr->size)) {
	    nodePtr = parentPtr->nextPtr;
	    parentPtr = parentPtr->parentPtr;
	} else {
	    while (nodePtr) {
		if (byteIndex < (int) nodePtr->size) {
		    if (nodePtr->level > 0) {
			nodePtr = nodePtr->childPtr;
			continue;
		    }
		    /*
		     * We've found the right node, now search for the line.
		     */
14726
14727
14728
14729
14730
14731
14732
14733
14734
14735
14736
14737
14738
14739
14740
14741
14742
14743
14744
14745
14746
14747
14748
14749
14750

    for (nPtr = parentPtr->childPtr, idx = 0; nPtr != nodePtr; nPtr = nPtr->nextPtr) {
	nodeStack[idx++] = nPtr;
    }
    nodePtr = idx ? nodeStack[--idx] : NULL;

    while (parentPtr) {
	if (!nodePtr || (!nodePtr->nextPtr && byteIndex >= (int)parentPtr->size)) {
	    nodePtr = parentPtr;
	    if ((parentPtr = parentPtr->parentPtr)) {
		for (nPtr = parentPtr->childPtr, idx = 0; nPtr != nodePtr; nPtr = nPtr->nextPtr) {
		    nodeStack[idx++] = nPtr;
		}
		nodePtr = idx ? nodeStack[--idx] : NULL;
	    }
	} else {
	    while (nodePtr) {
		if (byteIndex < (int)nodePtr->size) {
		    if (nodePtr->level > 0) {
			parentPtr = nodePtr;
			idx = 0;
			for (nPtr = nodePtr->childPtr; nPtr; nPtr = nPtr->nextPtr) {
			    nodeStack[idx++] = nPtr;
			}
			nodePtr = idx ? nodeStack[--idx] : NULL;







|









|







14727
14728
14729
14730
14731
14732
14733
14734
14735
14736
14737
14738
14739
14740
14741
14742
14743
14744
14745
14746
14747
14748
14749
14750
14751

    for (nPtr = parentPtr->childPtr, idx = 0; nPtr != nodePtr; nPtr = nPtr->nextPtr) {
	nodeStack[idx++] = nPtr;
    }
    nodePtr = idx ? nodeStack[--idx] : NULL;

    while (parentPtr) {
	if (!nodePtr || (!nodePtr->nextPtr && byteIndex >= (int) parentPtr->size)) {
	    nodePtr = parentPtr;
	    if ((parentPtr = parentPtr->parentPtr)) {
		for (nPtr = parentPtr->childPtr, idx = 0; nPtr != nodePtr; nPtr = nPtr->nextPtr) {
		    nodeStack[idx++] = nPtr;
		}
		nodePtr = idx ? nodeStack[--idx] : NULL;
	    }
	} else {
	    while (nodePtr) {
		if (byteIndex < (int) nodePtr->size) {
		    if (nodePtr->level > 0) {
			parentPtr = nodePtr;
			idx = 0;
			for (nPtr = nodePtr->childPtr; nPtr; nPtr = nPtr->nextPtr) {
			    nodeStack[idx++] = nPtr;
			}
			nodePtr = idx ? nodeStack[--idx] : NULL;
15885
15886
15887
15888
15889
15890
15891
15892

15893
15894
15895
15896
15897
15898
15899

static bool
CheckSections(
    const TkTextLine *linePtr)	/* Pointer to line with sections. */
{
    const TkTextSection *sectionPtr = linePtr->segPtr->sectionPtr;
    const TkTextSegment *segPtr;
    unsigned numSegs, size, length, count, lineSize = 0;


    if (!sectionPtr) {
	Tcl_Panic("CheckSections: segment has no section");
    }
    if (linePtr->segPtr->sectionPtr->segPtr != linePtr->segPtr) {
	Tcl_Panic("CheckSections: first segment has wrong section pointer");
    }







|
>







15886
15887
15888
15889
15890
15891
15892
15893
15894
15895
15896
15897
15898
15899
15900
15901

static bool
CheckSections(
    const TkTextLine *linePtr)	/* Pointer to line with sections. */
{
    const TkTextSection *sectionPtr = linePtr->segPtr->sectionPtr;
    const TkTextSegment *segPtr;
    unsigned numSegs, length, count;
    int size, lineSize = 0;

    if (!sectionPtr) {
	Tcl_Panic("CheckSections: segment has no section");
    }
    if (linePtr->segPtr->sectionPtr->segPtr != linePtr->segPtr) {
	Tcl_Panic("CheckSections: first segment has wrong section pointer");
    }

Changes to generic/tkTextDisp.c.

16
17
18
19
20
21
22
23
24
25
26
27
28
29




30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

#include "tkText.h"
#include "tkTextTagSet.h"
#include "tkRangeList.h"
#include "tkInt.h"

#ifdef _WIN32
#include "tkWinInt.h"
#elif defined(__CYGWIN__)
#include "tkUnixInt.h"
#endif

#ifdef MAC_OSX_TK
#include "tkMacOSXInt.h"




#endif

#include <stdlib.h>
#include <assert.h>

#ifndef MIN
# define MIN(a,b) (a < b ? a : b)
#endif
#ifndef MAX
# define MAX(a,b) (a < b ? b : a)
#endif

#if NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * "Calculations of line pixel heights and the size of the vertical







|

|



|
>
>
>
>












|







16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

#include "tkText.h"
#include "tkTextTagSet.h"
#include "tkRangeList.h"
#include "tkInt.h"

#ifdef _WIN32
# include "tkWinInt.h"
#elif defined(__CYGWIN__)
# include "tkUnixInt.h"
#endif

#ifdef MAC_OSX_TK
# include "tkMacOSXInt.h"
/* Version 8.5 has forgotten to define this constant. */
# ifndef TK_DO_NOT_DRAW
#  define TK_DO_NOT_DRAW 0x80
# endif
#endif

#include <stdlib.h>
#include <assert.h>

#ifndef MIN
# define MIN(a,b) (a < b ? a : b)
#endif
#ifndef MAX
# define MAX(a,b) (a < b ? b : a)
#endif

#ifdef NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * "Calculations of line pixel heights and the size of the vertical
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 * 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, UpdateLineMetrics.
 *
 * 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.
 */

/*







|







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
 * 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, UpdateOneLine, UpdateLineMetrics.
 *
 * 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.
 */

/*
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
     * Information used for scrolling:
     */

    int32_t newXPixelOffset;	/* Desired x scroll position, measured as the number of pixels
    				 * off-screen to the left for a line with no left margin. */
    int32_t curXPixelOffset;	/* Actual x scroll position, measured as the number of pixels
    				 * off-screen to the left. */
    int32_t 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. */
    PixelPos curPixelPos;	/* Most recent pixel position, used for the "watch" command. */
    PixelPos prevPixelPos;	/* Previous pixel position, used for the "watch" command. */

    /*
     * The following information is used to implement scanning:







|







401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
     * Information used for scrolling:
     */

    int32_t newXPixelOffset;	/* Desired x scroll position, measured as the number of pixels
    				 * off-screen to the left for a line with no left margin. */
    int32_t curXPixelOffset;	/* Actual x scroll position, measured as the number of pixels
    				 * off-screen to the left. */
    uint32_t 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. */
    PixelPos curPixelPos;	/* Most recent pixel position, used for the "watch" command. */
    PixelPos prevPixelPos;	/* Previous pixel position, used for the "watch" command. */

    /*
     * The following information is used to implement scanning:
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
    const char *brks;		/* Buffer for line break information (for TEXT_WRAPMODE_CODEPOINT). */
    TkTextIndex index;		/* Current index. */
    unsigned countChunks;	/* Number of chunks in current display line. */
    unsigned numBytesSoFar;	/* The number of processed bytes (so far). */
    unsigned byteOffset;	/* The byte offset to start of logical line. */
    unsigned dispLineOffset;	/* The byte offset to start of display line. */
    int increaseNumBytes;	/* Increase number of consumed bytes to realize spelling changes. */
    int decreaseNumBytes;	/* Decrease number of displayable bytes to realize spelling changes. */
    int displayLineNo;		/* Current display line number. */
    int rMargin;		/* Right margin width for line. */
    int hyphenRule;		/* Hyphenation rule applied to last char chunk (only in hyphenation
    				 * has been applied). */
    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. */







|
|







552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
    const char *brks;		/* Buffer for line break information (for TEXT_WRAPMODE_CODEPOINT). */
    TkTextIndex index;		/* Current index. */
    unsigned countChunks;	/* Number of chunks in current display line. */
    unsigned numBytesSoFar;	/* The number of processed bytes (so far). */
    unsigned byteOffset;	/* The byte offset to start of logical line. */
    unsigned dispLineOffset;	/* The byte offset to start of display line. */
    int increaseNumBytes;	/* Increase number of consumed bytes to realize spelling changes. */
    unsigned decreaseNumBytes;	/* Decrease number of displayable bytes to realize spelling changes. */
    unsigned displayLineNo;	/* Current display line number. */
    int rMargin;		/* Right margin width for line. */
    int hyphenRule;		/* Hyphenation rule applied to last char chunk (only in hyphenation
    				 * has been applied). */
    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. */
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
} LayoutData;

typedef struct DisplayInfo {
    int byteOffset;		/* Byte offset to start of display line (subtract this offset to
    				 * get the index of display line start). */
    int nextByteOffset;		/* Byte offset to start of next display line (add this offset to
    				 * get the index of next display line start). */
    int displayLineNo;		/* Number of display line. */
    unsigned numDispLines;	/* Total number of display lines belonging to corresponding logical
    				 * line (so far). */
    int pixels;			/* Total height of logical line (so far). */
    bool isComplete;		/* The display line metric is complete for this logical line? */
    const TkTextDispLineEntry *entry;
    				/* Pointer to entry in display pixel info for displayLineNo. Note
				 * that the predecessing entries can be accessed, but not the successing







|







591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
} LayoutData;

typedef struct DisplayInfo {
    int byteOffset;		/* Byte offset to start of display line (subtract this offset to
    				 * get the index of display line start). */
    int nextByteOffset;		/* Byte offset to start of next display line (add this offset to
    				 * get the index of next display line start). */
    unsigned displayLineNo;	/* Number of display line. */
    unsigned numDispLines;	/* Total number of display lines belonging to corresponding logical
    				 * line (so far). */
    int pixels;			/* Total height of logical line (so far). */
    bool isComplete;		/* The display line metric is complete for this logical line? */
    const TkTextDispLineEntry *entry;
    				/* Pointer to entry in display pixel info for displayLineNo. Note
				 * that the predecessing entries can be accessed, but not the successing
713
714
715
716
717
718
719
720


721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
			    FreeDLineAction action);
static void		FreeStyle(TkText *textPtr, TextStyle *stylePtr);
static TextStyle *	GetStyle(TkText *textPtr, TkTextSegment *segPtr);
static void		UpdateDefaultStyle(TkText *textPtr);
static void		GetXView(Tcl_Interp *interp, TkText *textPtr, bool report);
static void		GetYView(Tcl_Interp *interp, TkText *textPtr, bool report);
static unsigned		GetYPixelCount(TkText *textPtr, DLine *dlPtr);
static DLine *		LayoutDLine(const TkTextIndex *indexPtr, int displayLineNo);


static bool		MeasureUp(TkText *textPtr, const TkTextIndex *srcPtr, int distance,
			    TkTextIndex *dstPtr, int32_t *overlap);
static bool		MeasureDown(TkText *textPtr, TkTextIndex *srcPtr, int distance,
			    int32_t *overlap, bool saveDisplayLines);
static int		NextTabStop(unsigned tabWidth, int x, int tabOrigin);
static void		UpdateDisplayInfo(TkText *textPtr);
static void		YScrollByLines(TkText *textPtr, int offset);
static void		YScrollByPixels(TkText *textPtr, int offset);
static void		TextInvalidateRegion(TkText *textPtr, TkRegion region);
static void		TextInvalidateLineMetrics(TkText *textPtr, TkTextLine *linePtr,
			    unsigned lineCount, TkTextInvalidateAction action);
static int		CalculateDisplayLineHeight(TkText *textPtr, const TkTextIndex *indexPtr,
			    unsigned *byteCountPtr);
static TkTextDispChunk * DLineChunkOfX(TkText *textPtr, DLine *dlPtr, int x, TkTextIndex *indexPtr,
			    bool *nearby);
static void		DLineIndexOfX(TkText *textPtr, TkTextDispChunk *chunkPtr, int x,
			    TkTextIndex *indexPtr);
static int		DLineXOfIndex(TkText *textPtr, DLine *dlPtr, int byteIndex);
static ScrollMethod	TextGetScrollInfoObj(Tcl_Interp *interp, TkText *textPtr, int objc,
			    Tcl_Obj *const objv[], double *dblPtr, int *intPtr);
static void		InvokeAsyncUpdateLineMetrics(TkText *textPtr);
static void		InvokeAsyncUpdateYScrollbar(TkText *textPtr);
static void		AsyncUpdateYScrollbar(ClientData clientData);
static void		AsyncUpdateLineMetrics(ClientData clientData);
static void		UpdateLineMetrics(TkText *textPtr, unsigned doThisMuch);







|
>
>

















|







717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
			    FreeDLineAction action);
static void		FreeStyle(TkText *textPtr, TextStyle *stylePtr);
static TextStyle *	GetStyle(TkText *textPtr, TkTextSegment *segPtr);
static void		UpdateDefaultStyle(TkText *textPtr);
static void		GetXView(Tcl_Interp *interp, TkText *textPtr, bool report);
static void		GetYView(Tcl_Interp *interp, TkText *textPtr, bool report);
static unsigned		GetYPixelCount(TkText *textPtr, DLine *dlPtr);
static DLine *		LayoutDLine(const TkTextIndex *indexPtr, unsigned displayLineNo);
static int		UpdateOneLine(TkText *textPtr, TkTextLine *linePtr, TkTextIndex *indexPtr,
			    unsigned maxDispLines);
static bool		MeasureUp(TkText *textPtr, const TkTextIndex *srcPtr, int distance,
			    TkTextIndex *dstPtr, int32_t *overlap);
static bool		MeasureDown(TkText *textPtr, TkTextIndex *srcPtr, int distance,
			    int32_t *overlap, bool saveDisplayLines);
static int		NextTabStop(unsigned tabWidth, int x, int tabOrigin);
static void		UpdateDisplayInfo(TkText *textPtr);
static void		YScrollByLines(TkText *textPtr, int offset);
static void		YScrollByPixels(TkText *textPtr, int offset);
static void		TextInvalidateRegion(TkText *textPtr, TkRegion region);
static void		TextInvalidateLineMetrics(TkText *textPtr, TkTextLine *linePtr,
			    unsigned lineCount, TkTextInvalidateAction action);
static int		CalculateDisplayLineHeight(TkText *textPtr, const TkTextIndex *indexPtr,
			    unsigned *byteCountPtr);
static TkTextDispChunk * DLineChunkOfX(TkText *textPtr, DLine *dlPtr, int x, TkTextIndex *indexPtr,
			    bool *nearby);
static void		DLineIndexOfX(TkText *textPtr, TkTextDispChunk *chunkPtr, int x,
			    TkTextIndex *indexPtr);
static int		DLineXOfIndex(TkText *textPtr, DLine *dlPtr, unsigned byteIndex);
static ScrollMethod	TextGetScrollInfoObj(Tcl_Interp *interp, TkText *textPtr, int objc,
			    Tcl_Obj *const objv[], double *dblPtr, int *intPtr);
static void		InvokeAsyncUpdateLineMetrics(TkText *textPtr);
static void		InvokeAsyncUpdateYScrollbar(TkText *textPtr);
static void		AsyncUpdateYScrollbar(ClientData clientData);
static void		AsyncUpdateLineMetrics(ClientData clientData);
static void		UpdateLineMetrics(TkText *textPtr, unsigned doThisMuch);
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
    TEXT_DISP_ELIDED,	/* type */
    NULL,		/* displayProc */
    NULL,		/* undisplayProc */
    ElideMeasureProc,	/* measureProc */
    ElideBboxProc,	/* bboxProc */
};

#if !NDEBUG
/*
 * The following counters keep statistics about redisplay that can be checked
 * to see how clever this code is at reducing redisplays.
 */

typedef struct Statistic {
    unsigned numRedisplays;	/* Number of calls to DisplayText. */







|







821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
    TEXT_DISP_ELIDED,	/* type */
    NULL,		/* displayProc */
    NULL,		/* undisplayProc */
    ElideMeasureProc,	/* measureProc */
    ElideBboxProc,	/* bboxProc */
};

#ifndef NDEBUG
/*
 * The following counters keep statistics about redisplay that can be checked
 * to see how clever this code is at reducing redisplays.
 */

typedef struct Statistic {
    unsigned numRedisplays;	/* Number of calls to DisplayText. */
935
936
937
938
939
940
941


942
943
944
945
946
947
948
 */

static const char doNotBreakAtAll[8] = {
    LINEBREAK_NOBREAK, LINEBREAK_NOBREAK, LINEBREAK_NOBREAK, LINEBREAK_NOBREAK,
    LINEBREAK_NOBREAK, LINEBREAK_NOBREAK, LINEBREAK_NOBREAK, LINEBREAK_NOBREAK };

static bool IsPowerOf2(unsigned n) { return !(n & (n - 1)); }



static unsigned
NextPowerOf2(uint32_t n)
{
    --n;
    n |= n >> 1;
    n |= n >> 2;







>
>







941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
 */

static const char doNotBreakAtAll[8] = {
    LINEBREAK_NOBREAK, LINEBREAK_NOBREAK, LINEBREAK_NOBREAK, LINEBREAK_NOBREAK,
    LINEBREAK_NOBREAK, LINEBREAK_NOBREAK, LINEBREAK_NOBREAK, LINEBREAK_NOBREAK };

static bool IsPowerOf2(unsigned n) { return !(n & (n - 1)); }

static bool IsBlank(int ch) { return ch == ' ' || ch == '\t'; }

static unsigned
NextPowerOf2(uint32_t n)
{
    --n;
    n |= n >> 1;
    n |= n >> 2;
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383

    ranges = indexPtr->textPtr->dInfoPtr->lineMetricUpdateRanges;

    if (TkRangeListIsEmpty(ranges)) {
	return true;
    }

    return TkTextIndexGetLineNumber(indexPtr, indexPtr->textPtr) < TkRangeListLow(ranges);
}

/*
 *----------------------------------------------------------------------
 *
 * InvokeAsyncUpdateYScrollbar --
 *







|







1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391

    ranges = indexPtr->textPtr->dInfoPtr->lineMetricUpdateRanges;

    if (TkRangeListIsEmpty(ranges)) {
	return true;
    }

    return (int) TkTextIndexGetLineNumber(indexPtr, indexPtr->textPtr) < TkRangeListLow(ranges);
}

/*
 *----------------------------------------------------------------------
 *
 * InvokeAsyncUpdateYScrollbar --
 *
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563

#if TK_CHECK_ALLOCS
    if (hookStatFunc) {
	atexit(AllocStatistic);
	hookStatFunc = false;
    }
#endif
#if !NDEBUG
    if (!stats.perfFuncIsHooked) {
	atexit(PerfStatistic);
	stats.perfFuncIsHooked = true;
    }
#endif
}
/*







|







1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571

#if TK_CHECK_ALLOCS
    if (hookStatFunc) {
	atexit(AllocStatistic);
	hookStatFunc = false;
    }
#endif
#ifndef NDEBUG
    if (!stats.perfFuncIsHooked) {
	atexit(PerfStatistic);
	stats.perfFuncIsHooked = true;
    }
#endif
}
/*
1844
1845
1846
1847
1848
1849
1850

1851
1852
1853

1854
1855
1856
1857
1858
1859
1860
    styleValues.hyphenRules = textPtr->hyphenRulesPtr ? textPtr->hyphenRules : TK_TEXT_HYPHEN_MASK;

    isSelected = false;

    for ( ; tagPtr; tagPtr = tagPtr->nextPtr) {
	Tk_3DBorder border;
        XColor *fgColor;


	border = tagPtr->border;
        fgColor = tagPtr->fgColor;


	/*
	 * 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.
	 */








>



>







1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
    styleValues.hyphenRules = textPtr->hyphenRulesPtr ? textPtr->hyphenRules : TK_TEXT_HYPHEN_MASK;

    isSelected = false;

    for ( ; tagPtr; tagPtr = tagPtr->nextPtr) {
	Tk_3DBorder border;
        XColor *fgColor;
	int priority;

	border = tagPtr->border;
        fgColor = tagPtr->fgColor;
	priority = tagPtr->priority;

	/*
	 * 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.
	 */

1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020

        if (tagPtr->selBorder && isSelected) {
            border = tagPtr->selBorder;
        }
        if (tagPtr->selFgColor != None && isSelected) {
            fgColor = tagPtr->selFgColor;
        }
	if (border && tagPtr->priority > borderPrio) {
	    styleValues.border = border;
	    borderPrio = tagPtr->priority;
	}
	if (tagPtr->borderWidthPtr
		&& Tcl_GetString(tagPtr->borderWidthPtr)[0] != '\0'
		&& tagPtr->priority > borderWidthPrio) {
	    styleValues.borderWidth = tagPtr->borderWidth;
	    borderWidthPrio = tagPtr->priority;
	}
	if (tagPtr->reliefString && tagPtr->priority > reliefPrio) {
	    if (!styleValues.border) {
		styleValues.border = textPtr->border;
	    }
	    assert(tagPtr->relief < 8);
	    styleValues.relief = tagPtr->relief;
	    reliefPrio = tagPtr->priority;
	}
	if (tagPtr->bgStipple != None && tagPtr->priority > bgStipplePrio) {
	    styleValues.bgStipple = tagPtr->bgStipple;
	    bgStipplePrio = tagPtr->priority;
	}
	if (tagPtr->indentBgString != None && tagPtr->priority > indentBgPrio) {
	    assert(tagPtr->indentBg <= 1);
	    styleValues.indentBg = tagPtr->indentBg;
	    indentBgPrio = tagPtr->priority;
	}
	if (fgColor != None && tagPtr->priority > fgPrio) {
	    styleValues.fgColor = 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 && tagPtr->priority > justifyPrio) {
	    /* assert(tagPtr->justify < 8); always true due to range */
	    styleValues.justify = tagPtr->justify;
	    justifyPrio = tagPtr->priority;
	}
	if (tagPtr->lMargin1String && tagPtr->priority > lMargin1Prio) {
	    styleValues.lMargin1 = tagPtr->lMargin1;
	    lMargin1Prio = tagPtr->priority;
	}
	if (tagPtr->lMargin2String && tagPtr->priority > lMargin2Prio) {
	    styleValues.lMargin2 = tagPtr->lMargin2;
	    lMargin2Prio = tagPtr->priority;
	}
	if (tagPtr->lMarginColor && tagPtr->priority > lMarginColorPrio) {
	    styleValues.lMarginColor = tagPtr->lMarginColor;
	    lMarginColorPrio = tagPtr->priority;
	}
	if (tagPtr->offsetString && tagPtr->priority > offsetPrio) {
	    styleValues.offset = tagPtr->offset;
	    offsetPrio = tagPtr->priority;
	}
	if (tagPtr->overstrikeString && tagPtr->priority > overstrikePrio) {
	    assert(tagPtr->overstrike <= 1);
	    styleValues.overstrike = tagPtr->overstrike;
	    overstrikePrio = tagPtr->priority;
            if (tagPtr->overstrikeColor != None) {
                 styleValues.overstrikeColor = tagPtr->overstrikeColor;
            } else if (fgColor != None) {
                 styleValues.overstrikeColor = fgColor;
            }
	}
	if (tagPtr->rMarginString && tagPtr->priority > rMarginPrio) {
	    styleValues.rMargin = tagPtr->rMargin;
	    rMarginPrio = tagPtr->priority;
	}
	if (tagPtr->rMarginColor && tagPtr->priority > rMarginColorPrio) {
	    styleValues.rMarginColor = tagPtr->rMarginColor;
	    rMarginColorPrio = tagPtr->priority;
	}
	if (tagPtr->spacing1String && tagPtr->priority > spacing1Prio) {
	    styleValues.spacing1 = tagPtr->spacing1;
	    spacing1Prio = tagPtr->priority;
	}
	if (tagPtr->spacing2String && tagPtr->priority > spacing2Prio) {
	    styleValues.spacing2 = tagPtr->spacing2;
	    spacing2Prio = tagPtr->priority;
	}
	if (tagPtr->spacing3String && tagPtr->priority > spacing3Prio) {
	    styleValues.spacing3 = tagPtr->spacing3;
	    spacing3Prio = tagPtr->priority;
	}
	if (tagPtr->tabStringPtr && tagPtr->priority > tabPrio) {
	    styleValues.tabArrayPtr = tagPtr->tabArrayPtr;
	    tabPrio = tagPtr->priority;
	}
	if (tagPtr->tabStyle != TK_TEXT_TABSTYLE_NONE && tagPtr->priority > tabStylePrio) {
	    assert(tagPtr->tabStyle < 8);
	    styleValues.tabStyle = tagPtr->tabStyle;
	    tabStylePrio = tagPtr->priority;
	}
	if (tagPtr->eolColor && tagPtr->priority > eolColorPrio) {
	    styleValues.eolColor = tagPtr->eolColor;
	    eolColorPrio = tagPtr->priority;
	}
	if (tagPtr->hyphenColor && tagPtr->priority > hyphenColorPrio) {
	    styleValues.hyphenColor = tagPtr->hyphenColor;
	    hyphenColorPrio = tagPtr->priority;
	}
	if (tagPtr->underlineString && tagPtr->priority > underlinePrio) {
	    assert(tagPtr->underline <= 1);
	    styleValues.underline = tagPtr->underline;
	    underlinePrio = tagPtr->priority;
            if (tagPtr->underlineColor != None) {
		styleValues.underlineColor = tagPtr->underlineColor;
            } else if (fgColor != None) {
		styleValues.underlineColor = fgColor;
            }
	}
	if (tagPtr->elideString && tagPtr->priority > elidePrio) {
	    assert(tagPtr->elide <= 1);
	    styleValues.elide = tagPtr->elide;
	    elidePrio = tagPtr->priority;
	}
	if (tagPtr->langPtr && tagPtr->priority > langPrio) {
	    styleValues.lang = tagPtr->lang;
	    langPrio = tagPtr->priority;
	}
	if (tagPtr->hyphenRulesPtr && tagPtr->priority > hyphenRulesPrio) {
	    styleValues.hyphenRules = tagPtr->hyphenRules;
	    hyphenRulesPrio = tagPtr->priority;
	}
	if (tagPtr->wrapMode != TEXT_WRAPMODE_NULL && tagPtr->priority > wrapPrio) {
	    /* assert(tagPtr->wrapMode < 8); always true due to range */
	    styleValues.wrapMode = tagPtr->wrapMode;
	    wrapPrio = tagPtr->priority;
	}
    }

    /*
     * Use an existing style if there's one around that matches.
     */








|

|



|

|

|





|

|

|

|


|

|

|

|

|

|

|

|


|

|

|

|

|

|

|

|

|

|


|






|

|

|

|

|

|

|

|

|

|

|

|

|


|

|

|

|

|

|


|






|


|

|

|

|

|

|


|







1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030

        if (tagPtr->selBorder && isSelected) {
            border = tagPtr->selBorder;
        }
        if (tagPtr->selFgColor != None && isSelected) {
            fgColor = tagPtr->selFgColor;
        }
	if (border && priority > borderPrio) {
	    styleValues.border = border;
	    borderPrio = priority;
	}
	if (tagPtr->borderWidthPtr
		&& Tcl_GetString(tagPtr->borderWidthPtr)[0] != '\0'
		&& priority > borderWidthPrio) {
	    styleValues.borderWidth = tagPtr->borderWidth;
	    borderWidthPrio = priority;
	}
	if (tagPtr->reliefString && priority > reliefPrio) {
	    if (!styleValues.border) {
		styleValues.border = textPtr->border;
	    }
	    assert(tagPtr->relief < 8);
	    styleValues.relief = tagPtr->relief;
	    reliefPrio = priority;
	}
	if (tagPtr->bgStipple != None && priority > bgStipplePrio) {
	    styleValues.bgStipple = tagPtr->bgStipple;
	    bgStipplePrio = priority;
	}
	if (tagPtr->indentBgString != None && priority > indentBgPrio) {
	    assert(tagPtr->indentBg <= 1);
	    styleValues.indentBg = tagPtr->indentBg;
	    indentBgPrio = priority;
	}
	if (fgColor != None && priority > fgPrio) {
	    styleValues.fgColor = fgColor;
	    fgPrio = priority;
	}
	if (tagPtr->tkfont != None && priority > fontPrio) {
	    styleValues.tkfont = tagPtr->tkfont;
	    fontPrio = priority;
	}
	if (tagPtr->fgStipple != None && priority > fgStipplePrio) {
	    styleValues.fgStipple = tagPtr->fgStipple;
	    fgStipplePrio = priority;
	}
	if (tagPtr->justifyString && priority > justifyPrio) {
	    /* assert(tagPtr->justify < 8); always true due to range */
	    styleValues.justify = tagPtr->justify;
	    justifyPrio = priority;
	}
	if (tagPtr->lMargin1String && priority > lMargin1Prio) {
	    styleValues.lMargin1 = tagPtr->lMargin1;
	    lMargin1Prio = priority;
	}
	if (tagPtr->lMargin2String && priority > lMargin2Prio) {
	    styleValues.lMargin2 = tagPtr->lMargin2;
	    lMargin2Prio = priority;
	}
	if (tagPtr->lMarginColor && priority > lMarginColorPrio) {
	    styleValues.lMarginColor = tagPtr->lMarginColor;
	    lMarginColorPrio = priority;
	}
	if (tagPtr->offsetString && priority > offsetPrio) {
	    styleValues.offset = tagPtr->offset;
	    offsetPrio = priority;
	}
	if (tagPtr->overstrikeString && priority > overstrikePrio) {
	    assert(tagPtr->overstrike <= 1);
	    styleValues.overstrike = tagPtr->overstrike;
	    overstrikePrio = priority;
            if (tagPtr->overstrikeColor != None) {
                 styleValues.overstrikeColor = tagPtr->overstrikeColor;
            } else if (fgColor != None) {
                 styleValues.overstrikeColor = fgColor;
            }
	}
	if (tagPtr->rMarginString && priority > rMarginPrio) {
	    styleValues.rMargin = tagPtr->rMargin;
	    rMarginPrio = priority;
	}
	if (tagPtr->rMarginColor && priority > rMarginColorPrio) {
	    styleValues.rMarginColor = tagPtr->rMarginColor;
	    rMarginColorPrio = priority;
	}
	if (tagPtr->spacing1String && priority > spacing1Prio) {
	    styleValues.spacing1 = tagPtr->spacing1;
	    spacing1Prio = priority;
	}
	if (tagPtr->spacing2String && priority > spacing2Prio) {
	    styleValues.spacing2 = tagPtr->spacing2;
	    spacing2Prio = priority;
	}
	if (tagPtr->spacing3String && priority > spacing3Prio) {
	    styleValues.spacing3 = tagPtr->spacing3;
	    spacing3Prio = priority;
	}
	if (tagPtr->tabStringPtr && priority > tabPrio) {
	    styleValues.tabArrayPtr = tagPtr->tabArrayPtr;
	    tabPrio = priority;
	}
	if (tagPtr->tabStyle != TK_TEXT_TABSTYLE_NONE && priority > tabStylePrio) {
	    assert(tagPtr->tabStyle < 8);
	    styleValues.tabStyle = tagPtr->tabStyle;
	    tabStylePrio = priority;
	}
	if (tagPtr->eolColor && priority > eolColorPrio) {
	    styleValues.eolColor = tagPtr->eolColor;
	    eolColorPrio = priority;
	}
	if (tagPtr->hyphenColor && priority > hyphenColorPrio) {
	    styleValues.hyphenColor = tagPtr->hyphenColor;
	    hyphenColorPrio = priority;
	}
	if (tagPtr->underlineString && priority > underlinePrio) {
	    assert(tagPtr->underline <= 1);
	    styleValues.underline = tagPtr->underline;
	    underlinePrio = priority;
            if (tagPtr->underlineColor != None) {
		styleValues.underlineColor = tagPtr->underlineColor;
            } else if (fgColor != None) {
		styleValues.underlineColor = fgColor;
            }
	}
	if (tagPtr->elideString && priority > elidePrio) {
	    assert(tagPtr->elide <= 1);
	    styleValues.elide = tagPtr->elide;
	    elidePrio = priority;
	}
	if (tagPtr->langPtr && priority > langPrio) {
	    styleValues.lang = tagPtr->lang;
	    langPrio = priority;
	}
	if (tagPtr->hyphenRulesPtr && priority > hyphenRulesPrio) {
	    styleValues.hyphenRules = tagPtr->hyphenRules;
	    hyphenRulesPrio = priority;
	}
	if (tagPtr->wrapMode != TEXT_WRAPMODE_NULL && priority > wrapPrio) {
	    /* assert(tagPtr->wrapMode < 8); always true due to range */
	    styleValues.wrapMode = tagPtr->wrapMode;
	    wrapPrio = priority;
	}
    }

    /*
     * Use an existing style if there's one around that matches.
     */

2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
    unsigned epoch = textPtr->dInfoPtr->lineMetricUpdateEpoch;
    TkTextPixelInfo *pixelInfo = TkBTreeLinePixelInfo(textPtr, linePtr);
    unsigned oldNumDispLines = TkBTreeGetNumberOfDisplayLines(pixelInfo);
    TkTextDispLineInfo *dispLineInfo;
    TkTextLine *nextLogicalLinePtr;

    assert(dlPtr->byteCount > 0);
    assert(dlPtr->displayLineNo >= 0);
    assert(linePtr->logicalLine);
    assert(linePtr == TkBTreeGetLogicalLine(
	    textPtr->sharedTextPtr, textPtr, TkTextIndexGetLine(&dlPtr->index)));

    if (pixelInfo->epoch == epoch) {
	int lineNo = TkBTreeLinesTo(textPtr->sharedTextPtr->tree, textPtr, linePtr, NULL);








<







2359
2360
2361
2362
2363
2364
2365

2366
2367
2368
2369
2370
2371
2372
    unsigned epoch = textPtr->dInfoPtr->lineMetricUpdateEpoch;
    TkTextPixelInfo *pixelInfo = TkBTreeLinePixelInfo(textPtr, linePtr);
    unsigned oldNumDispLines = TkBTreeGetNumberOfDisplayLines(pixelInfo);
    TkTextDispLineInfo *dispLineInfo;
    TkTextLine *nextLogicalLinePtr;

    assert(dlPtr->byteCount > 0);

    assert(linePtr->logicalLine);
    assert(linePtr == TkBTreeGetLogicalLine(
	    textPtr->sharedTextPtr, textPtr, TkTextIndexGetLine(&dlPtr->index)));

    if (pixelInfo->epoch == epoch) {
	int lineNo = TkBTreeLinesTo(textPtr->sharedTextPtr->tree, textPtr, linePtr, NULL);

2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
LayoutFinalizeCharInfo(
    LayoutData *data,
    bool gotTab)
{
    CharInfo *ciPtr = data->chunkPtr->clientData;

    assert(data->trimSpaces ?
	    data->chunkPtr->numBytes >= ciPtr->numBytes :
	    data->chunkPtr->numBytes == ciPtr->numBytes);

    /*
     * Update the character information. Take into account that we don't want
     * to display the newline character.
     */

    if (ciPtr->u.chars[ciPtr->baseOffset + ciPtr->numBytes - 1] == '\n') {







|
|







2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
LayoutFinalizeCharInfo(
    LayoutData *data,
    bool gotTab)
{
    CharInfo *ciPtr = data->chunkPtr->clientData;

    assert(data->trimSpaces ?
	    (int) data->chunkPtr->numBytes >= ciPtr->numBytes :
	    (int) data->chunkPtr->numBytes == ciPtr->numBytes);

    /*
     * Update the character information. Take into account that we don't want
     * to display the newline character.
     */

    if (ciPtr->u.chars[ciPtr->baseOffset + ciPtr->numBytes - 1] == '\n') {
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
			chunkPtr->skipFirstChar = true;
		    }
		}
	    }
	}

	if (data->trimSpaces) {
	    int i;

	    for (i = 0; i < maxBytes; ++i) {
		if (base[i] == ' ' && base[i + 1] == ' ') {
		    while (base[i] == ' ') {
			++i;
		    }
		    maxBytes = i;
		    data->skipSpaces = true;
		    break;
		}
	    }
	}

	/*
	 * See if there is a tab in the current chunk; if so, only layout
	 * characters up to (and including) the tab.
	 */

	if (data->justify == TK_TEXT_JUSTIFY_LEFT) {
	    const char *p = base;
	    int i;

	    /* TODO: also TK_TEXT_JUSTIFY_RIGHT should support tabs */
	    /* TODO: direction of tabs should depend on gravity of insert mark?! */

	    for (i = 0; i < maxBytes; ++i, ++p) {
		if (*p == '\t') {
		    maxBytes = i + 1;







|




















|







3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
			chunkPtr->skipFirstChar = true;
		    }
		}
	    }
	}

	if (data->trimSpaces) {
	    unsigned i;

	    for (i = 0; i < maxBytes; ++i) {
		if (base[i] == ' ' && base[i + 1] == ' ') {
		    while (base[i] == ' ') {
			++i;
		    }
		    maxBytes = i;
		    data->skipSpaces = true;
		    break;
		}
	    }
	}

	/*
	 * See if there is a tab in the current chunk; if so, only layout
	 * characters up to (and including) the tab.
	 */

	if (data->justify == TK_TEXT_JUSTIFY_LEFT) {
	    const char *p = base;
	    unsigned i;

	    /* TODO: also TK_TEXT_JUSTIFY_RIGHT should support tabs */
	    /* TODO: direction of tabs should depend on gravity of insert mark?! */

	    for (i = 0; i < maxBytes; ++i, ++p) {
		if (*p == '\t') {
		    maxBytes = i + 1;
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829
3830
3831
		bool fits;

		data->x = prevChunkPtr->x + prevChunkPtr->width;
		if (prevChunkPtr == data->firstCharChunkPtr && prevChunkPtr->breakIndex <= 0) {
		    data->maxX = INT_MAX; /* The hyphen must be shown. */
		}
		fits = LayoutChars(data, hyphenSegPtr, hyphenSegPtr->body.hyphen.textSize, 0);
		assert(!fits || data->chunkPtr->numBytes == hyphenSegPtr->body.hyphen.textSize);
		hyphenChunkPtr = data->chunkPtr;
		data->maxX = maxX;

		if (fits) {
		    /* The hyphen fits, so we're done. */
		    LayoutFinalizeChunk(data);
		    hyphenChunkPtr->numBytes = 1 + data->increaseNumBytes;







|







3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
3836
3837
3838
3839
3840
		bool fits;

		data->x = prevChunkPtr->x + prevChunkPtr->width;
		if (prevChunkPtr == data->firstCharChunkPtr && prevChunkPtr->breakIndex <= 0) {
		    data->maxX = INT_MAX; /* The hyphen must be shown. */
		}
		fits = LayoutChars(data, hyphenSegPtr, hyphenSegPtr->body.hyphen.textSize, 0);
		assert(!fits || (int) data->chunkPtr->numBytes == hyphenSegPtr->body.hyphen.textSize);
		hyphenChunkPtr = data->chunkPtr;
		data->maxX = maxX;

		if (fits) {
		    /* The hyphen fits, so we're done. */
		    LayoutFinalizeChunk(data);
		    hyphenChunkPtr->numBytes = 1 + data->increaseNumBytes;
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
     * Now check if we must break because the line length have been exceeded. At this point
     * hyphenation is not involved.
     */

    if (data->breakChunkPtr
	    && (data->lastChunkPtr != data->breakChunkPtr
		|| (data->lastChunkPtr->breakIndex > 0
		    && data->lastChunkPtr->breakIndex != data->lastChunkPtr->numBytes))) {
	unsigned addNumBytes = 0;

	LayoutDestroyChunks(data);

	if (data->breakChunkPtr->breakIndex > 0 && data->breakChunkPtr->numSpaces > 0) {
	    const TkTextDispChunk *breakChunkPtr = data->breakChunkPtr;
	    const CharInfo *ciPtr = breakChunkPtr->clientData;
	    const char *p = ciPtr->u.chars + ciPtr->baseOffset + breakChunkPtr->breakIndex;
	    const char *q = Tcl_UtfPrev(p, ciPtr->u.chars + ciPtr->baseOffset);

	    if (IsExpandableSpace(q)
		    && !(breakChunkPtr->wrappedAtSpace
			&& breakChunkPtr->breakIndex == breakChunkPtr->numBytes)) {
		addNumBytes = p - q;
		data->breakChunkPtr->breakIndex -= addNumBytes;
		data->breakChunkPtr->numSpaces -= 1;
		data->numSpaces -= 1;
	    }
	}

	if (data->breakChunkPtr->breakIndex != data->breakChunkPtr->numBytes) {
	    TkTextSegment *segPtr;
	    TkTextDispChunk *chunkPtr = data->breakChunkPtr;
	    TkTextIndex index = *indexPtr;

	    LayoutUndisplay(data, chunkPtr);
	    data->chunkPtr = chunkPtr;
	    TkTextIndexForwBytes(data->textPtr, &index, chunkPtr->byteOffset, &index);







|












|







|







3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
     * Now check if we must break because the line length have been exceeded. At this point
     * hyphenation is not involved.
     */

    if (data->breakChunkPtr
	    && (data->lastChunkPtr != data->breakChunkPtr
		|| (data->lastChunkPtr->breakIndex > 0
		    && data->lastChunkPtr->breakIndex != (int) data->lastChunkPtr->numBytes))) {
	unsigned addNumBytes = 0;

	LayoutDestroyChunks(data);

	if (data->breakChunkPtr->breakIndex > 0 && data->breakChunkPtr->numSpaces > 0) {
	    const TkTextDispChunk *breakChunkPtr = data->breakChunkPtr;
	    const CharInfo *ciPtr = breakChunkPtr->clientData;
	    const char *p = ciPtr->u.chars + ciPtr->baseOffset + breakChunkPtr->breakIndex;
	    const char *q = Tcl_UtfPrev(p, ciPtr->u.chars + ciPtr->baseOffset);

	    if (IsExpandableSpace(q)
		    && !(breakChunkPtr->wrappedAtSpace
			&& breakChunkPtr->breakIndex == (int) breakChunkPtr->numBytes)) {
		addNumBytes = p - q;
		data->breakChunkPtr->breakIndex -= addNumBytes;
		data->breakChunkPtr->numSpaces -= 1;
		data->numSpaces -= 1;
	    }
	}

	if (data->breakChunkPtr->breakIndex != (int) data->breakChunkPtr->numBytes) {
	    TkTextSegment *segPtr;
	    TkTextDispChunk *chunkPtr = data->breakChunkPtr;
	    TkTextIndex index = *indexPtr;

	    LayoutUndisplay(data, chunkPtr);
	    data->chunkPtr = chunkPtr;
	    TkTextIndexForwBytes(data->textPtr, &index, chunkPtr->byteOffset, &index);
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
    return segPtr->typePtr == &tkTextCharType && segPtr->body.chars[offset] == ' ';
}

static DLine *
LayoutDLine(
    const TkTextIndex *indexPtr,/* Beginning of display line. May not necessarily point to
    				 * a character segment. */
    int displayLineNo)		/* Display line number of logical line, needed for caching. */
{
    TextDInfo *dInfoPtr;
    DLine *dlPtr;
    TkText *textPtr;
    StyleValues *sValPtr;
    TkTextDispChunk *chunkPtr;
    TkTextDispChunkSection *sectionPtr;







|







4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
4036
4037
4038
4039
    return segPtr->typePtr == &tkTextCharType && segPtr->body.chars[offset] == ' ';
}

static DLine *
LayoutDLine(
    const TkTextIndex *indexPtr,/* Beginning of display line. May not necessarily point to
    				 * a character segment. */
    unsigned displayLineNo)	/* Display line number of logical line, needed for caching. */
{
    TextDInfo *dInfoPtr;
    DLine *dlPtr;
    TkText *textPtr;
    StyleValues *sValPtr;
    TkTextDispChunk *chunkPtr;
    TkTextDispChunkSection *sectionPtr;
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
ComputeMissingMetric(
    TkText *textPtr,
    DisplayInfo *info,
    Threshold thresholdType,
    int threshold)
{
    int byteOffset, additionalLines;
    int displayLineNo;
    int *metricPtr = NULL; /* avoids compiler warning */
    unsigned viewHeight;
    TkTextIndex index;

    assert(threshold >= 0);

    if (info->isComplete) {







|







4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
ComputeMissingMetric(
    TkText *textPtr,
    DisplayInfo *info,
    Threshold thresholdType,
    int threshold)
{
    int byteOffset, additionalLines;
    unsigned displayLineNo;
    int *metricPtr = NULL; /* avoids compiler warning */
    unsigned viewHeight;
    TkTextIndex index;

    assert(threshold >= 0);

    if (info->isComplete) {
4890
4891
4892
4893
4894
4895
4896
4897
4898
4899
4900
4901
4902
4903
4904
    DLine *savedDLine;		/* usable saved display lines */
    DLine *prevSavedDLine;	/* last old unfreed display line */
    TkTextIndex index;
    TkTextLine *lastLinePtr;
    TkTextLine *linePtr;
    DisplayInfo info;
    int y, maxY, xPixelOffset, maxOffset;
    int displayLineNo;
    unsigned epoch;

    if (!(dInfoPtr->flags & DINFO_OUT_OF_DATE)) {
	return;
    }
    dInfoPtr->flags &= ~DINFO_OUT_OF_DATE;








|







4899
4900
4901
4902
4903
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
    DLine *savedDLine;		/* usable saved display lines */
    DLine *prevSavedDLine;	/* last old unfreed display line */
    TkTextIndex index;
    TkTextLine *lastLinePtr;
    TkTextLine *linePtr;
    DisplayInfo info;
    int y, maxY, xPixelOffset, maxOffset;
    unsigned displayLineNo;
    unsigned epoch;

    if (!(dInfoPtr->flags & DINFO_OUT_OF_DATE)) {
	return;
    }
    dInfoPtr->flags &= ~DINFO_OUT_OF_DATE;

5250
5251
5252
5253
5254
5255
5256



5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
			} else {
			    bottomLine = dlPtr;
			}
			topLine = dlPtr;
			DEBUG(dlPtr->flags |= LINKED);
			TK_TEXT_DEBUG(LogTextRelayout(textPtr, &dlPtr->index));
			spaceLeft -= dlPtr->height;



			info.displayLineNo -= 1;
			info.entry -= 1;
		    } while (spaceLeft > 0 && info.displayLineNo >= 0);

		    dInfoPtr->dLinePtr = topLine;
		    /* Delete remaining cached lines. */
		    FreeDLines(textPtr, info.dLinePtr, NULL, DLINE_FREE_TEMP);
		}
	    }








>
>
>


|







5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
			} else {
			    bottomLine = dlPtr;
			}
			topLine = dlPtr;
			DEBUG(dlPtr->flags |= LINKED);
			TK_TEXT_DEBUG(LogTextRelayout(textPtr, &dlPtr->index));
			spaceLeft -= dlPtr->height;
			if (info.displayLineNo == 0) {
			    break;
			}
			info.displayLineNo -= 1;
			info.entry -= 1;
		    } while (spaceLeft > 0);

		    dInfoPtr->dLinePtr = topLine;
		    /* Delete remaining cached lines. */
		    FreeDLines(textPtr, info.dLinePtr, NULL, DLINE_FREE_TEMP);
		}
	    }

5674
5675
5676
5677
5678
5679
5680



5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
	    dInfoPtr->lastDLinePtr = firstPtr->prevPtr;
	}
	dInfoPtr->dLinesInvalidated = true;
	assert(!dInfoPtr->dLinePtr || !dInfoPtr->dLinePtr->prevPtr);
	ReleaseLines(textPtr, firstPtr, lastPtr, action);
	break;
    case DLINE_SAVE: {



	if (!firstPtr || firstPtr == lastPtr) {
	    return NULL;
	}
	assert(firstPtr == dInfoPtr->dLinePtr);
	assert(lastPtr);

	unsigned epoch = dInfoPtr->lineMetricUpdateEpoch;
	DLine *dlPtr;

	assert(lastPtr->prevPtr);
	dInfoPtr->dLinePtr = lastPtr;

	/*
	 * Free all expired lines, we will only save valid lines.
	 */







>
>
>






|
<







5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702

5703
5704
5705
5706
5707
5708
5709
	    dInfoPtr->lastDLinePtr = firstPtr->prevPtr;
	}
	dInfoPtr->dLinesInvalidated = true;
	assert(!dInfoPtr->dLinePtr || !dInfoPtr->dLinePtr->prevPtr);
	ReleaseLines(textPtr, firstPtr, lastPtr, action);
	break;
    case DLINE_SAVE: {
	unsigned epoch;
	DLine *dlPtr;

	if (!firstPtr || firstPtr == lastPtr) {
	    return NULL;
	}
	assert(firstPtr == dInfoPtr->dLinePtr);
	assert(lastPtr);

	epoch = dInfoPtr->lineMetricUpdateEpoch;


	assert(lastPtr->prevPtr);
	dInfoPtr->dLinePtr = lastPtr;

	/*
	 * Free all expired lines, we will only save valid lines.
	 */
6588
6589
6590
6591
6592
6593
6594
6595
6596
6597
6598
6599
6600
6601
6602
		 * we actually re-layout. But in case of synchronous update we do a full
		 * computation.
		 */

		if (textPtr->syncTime > 0) {
		    maxDispLines = (doThisMuch - count + 7)/8;
		}
		count += 8*TkTextUpdateOneLine(textPtr, linePtr, &index, maxDispLines);

		if (pixelInfo->epoch & PARTIAL_COMPUTED_BIT) {
		    /*
		     * We didn't complete the logical line, because it produced very many
		     * display lines - it must be a long line wrapped many times.
		     */
		    return;







|







6602
6603
6604
6605
6606
6607
6608
6609
6610
6611
6612
6613
6614
6615
6616
		 * we actually re-layout. But in case of synchronous update we do a full
		 * computation.
		 */

		if (textPtr->syncTime > 0) {
		    maxDispLines = (doThisMuch - count + 7)/8;
		}
		count += 8*UpdateOneLine(textPtr, linePtr, &index, maxDispLines);

		if (pixelInfo->epoch & PARTIAL_COMPUTED_BIT) {
		    /*
		     * We didn't complete the logical line, because it produced very many
		     * display lines - it must be a long line wrapped many times.
		     */
		    return;
6647
6648
6649
6650
6651
6652
6653
6654
6655
6656
6657
6658
6659
6660
6661
6662
6663
6664
6665
6666
6667
6668

6669
6670
6671
6672
6673
6674
6675
    unsigned lineNum,		/* Start at this line. */
    unsigned endLine)		/* Go no further than this line. */
{
    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
    const TkRange *range;

    assert(lineNum <= endLine);
    assert(endLine <= TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr));
    assert(textPtr->sharedTextPtr->allowUpdateLineMetrics);

    dInfoPtr->insideLineMetricUpdate = true;

    if ((range = TkRangeListFindNearest(dInfoPtr->lineMetricUpdateRanges, lineNum))) {
	TkTextLine *linePtr = NULL;
	unsigned count = 0;
	int high = range->high;

	lineNum = range->low;
	endLine = MIN(endLine, TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr) - 1);

	while (true) {
	    const TkTextPixelInfo *pixelInfo;


	    if (lineNum > high) {
		/*
		 * Note that the update process has removed the finished lines.
		 */

		if (!(range = TkRangeListFindNearest(dInfoPtr->lineMetricUpdateRanges, lineNum))) {







|







|


|



>







6661
6662
6663
6664
6665
6666
6667
6668
6669
6670
6671
6672
6673
6674
6675
6676
6677
6678
6679
6680
6681
6682
6683
6684
6685
6686
6687
6688
6689
6690
    unsigned lineNum,		/* Start at this line. */
    unsigned endLine)		/* Go no further than this line. */
{
    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
    const TkRange *range;

    assert(lineNum <= endLine);
    assert((int) endLine <= TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr));
    assert(textPtr->sharedTextPtr->allowUpdateLineMetrics);

    dInfoPtr->insideLineMetricUpdate = true;

    if ((range = TkRangeListFindNearest(dInfoPtr->lineMetricUpdateRanges, lineNum))) {
	TkTextLine *linePtr = NULL;
	unsigned count = 0;
	unsigned high = range->high;

	lineNum = range->low;
	endLine = MIN((int) endLine, TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr) - 1);

	while (true) {
	    const TkTextPixelInfo *pixelInfo;
	    int firstLineNum;

	    if (lineNum > high) {
		/*
		 * Note that the update process has removed the finished lines.
		 */

		if (!(range = TkRangeListFindNearest(dInfoPtr->lineMetricUpdateRanges, lineNum))) {
6699
6700
6701
6702
6703
6704
6705
6706
6707
6708
6709
6710
6711
6712

6713
6714
6715
6716
6717
6718
6719
6720

6721
6722
6723
6724
6725
6726
6727

		/*
		 * This line is not (fully) up-to-date.
		 */

		TkTextIndexClear(&index, textPtr);
		TkTextIndexSetToStartOfLine2(&index, linePtr);
		TkTextUpdateOneLine(textPtr, linePtr, &index, UINT_MAX);
		assert(IsStartOfNotMergedLine(&index) || TkTextIndexIsEndOfText(&index));
		lineNum = NextLineNum(linePtr, lineNum, &index);
		linePtr = TkTextIndexGetLine(&index);
	    } else {
		int firstLineNum = lineNum;


		if (linePtr->nextPtr->logicalLine) {
		    linePtr = linePtr->nextPtr;
		    lineNum += 1;
		} else {
		    linePtr = TkBTreeNextLogicalLine(textPtr->sharedTextPtr, textPtr, linePtr);
		    lineNum = TkBTreeLinesTo(textPtr->sharedTextPtr->tree, textPtr, linePtr, NULL);
		}


		TkRangeListRemove(dInfoPtr->lineMetricUpdateRanges, firstLineNum, lineNum - 1);
	    }
	}
    }

    dInfoPtr->insideLineMetricUpdate = false;
    CheckIfLineMetricIsUpToDate(textPtr);







|

|
<

|
|
>
|
|
|
|
|
|
|

>







6714
6715
6716
6717
6718
6719
6720
6721
6722
6723

6724
6725
6726
6727
6728
6729
6730
6731
6732
6733
6734
6735
6736
6737
6738
6739
6740
6741
6742
6743

		/*
		 * This line is not (fully) up-to-date.
		 */

		TkTextIndexClear(&index, textPtr);
		TkTextIndexSetToStartOfLine2(&index, linePtr);
		UpdateOneLine(textPtr, linePtr, &index, UINT_MAX);
		assert(IsStartOfNotMergedLine(&index) || TkTextIndexIsEndOfText(&index));
		firstLineNum = -1; /* the update has removed the line numbers from range list */

	    } else {
		firstLineNum = lineNum;
	    }

	    if (linePtr->nextPtr->logicalLine) {
		linePtr = linePtr->nextPtr;
		lineNum += 1;
	    } else {
		linePtr = TkBTreeNextLogicalLine(textPtr->sharedTextPtr, textPtr, linePtr);
		lineNum = TkBTreeLinesTo(textPtr->sharedTextPtr->tree, textPtr, linePtr, NULL);
	    }

	    if (firstLineNum >= 0) {
		TkRangeListRemove(dInfoPtr->lineMetricUpdateRanges, firstLineNum, lineNum - 1);
	    }
	}
    }

    dInfoPtr->insideLineMetricUpdate = false;
    CheckIfLineMetricIsUpToDate(textPtr);
6814
6815
6816
6817
6818
6819
6820
6821
6822
6823
6824
6825
6826
6827
6828

	lineNum = TkBTreeLinesTo(textPtr->sharedTextPtr->tree, textPtr, linePtr, &deviation);

	assert(lineNum < totalLines);
	assert(deviation >= 0);

	if (deviation) {
	    lineCount -= MIN(lineCount, deviation);
	}

	if (action != TK_TEXT_INVALIDATE_ONLY
	    	&& !isMonospaced
		&& linePtr == TkBTreeGetStartLine(textPtr)
		&& lineCount + 1 >= totalLines) {
	    linePtr = NULL;







|







6830
6831
6832
6833
6834
6835
6836
6837
6838
6839
6840
6841
6842
6843
6844

	lineNum = TkBTreeLinesTo(textPtr->sharedTextPtr->tree, textPtr, linePtr, &deviation);

	assert(lineNum < totalLines);
	assert(deviation >= 0);

	if (deviation) {
	    lineCount -= MIN((int) lineCount, deviation);
	}

	if (action != TK_TEXT_INVALIDATE_ONLY
	    	&& !isMonospaced
		&& linePtr == TkBTreeGetStartLine(textPtr)
		&& lineCount + 1 >= totalLines) {
	    linePtr = NULL;
6974
6975
6976
6977
6978
6979
6980
6981
6982
6983
6984
6985
6986
6987
6988
		ranges = TkRangeListAdd(ranges, lineNum, lineNum);
		ResetPixelInfo(TkBTreeLinePixelInfo(textPtr,
			TkBTreeGetLogicalLine(textPtr->sharedTextPtr, textPtr, linePtr)));
	    }
	    break;
	}

	assert(TkRangeListIsEmpty(ranges) || TkRangeListHigh(ranges) < totalLines);
    } else {
	/*
	 * This invalidates the height of all lines in the widget.
	 */

	textPtr->dInfoPtr->lineMetricUpdateEpoch += 1;
	if (action == TK_TEXT_INVALIDATE_DELETE) {







|







6990
6991
6992
6993
6994
6995
6996
6997
6998
6999
7000
7001
7002
7003
7004
		ranges = TkRangeListAdd(ranges, lineNum, lineNum);
		ResetPixelInfo(TkBTreeLinePixelInfo(textPtr,
			TkBTreeGetLogicalLine(textPtr->sharedTextPtr, textPtr, linePtr)));
	    }
	    break;
	}

	assert(TkRangeListIsEmpty(ranges) || TkRangeListHigh(ranges) < (int) totalLines);
    } else {
	/*
	 * This invalidates the height of all lines in the widget.
	 */

	textPtr->dInfoPtr->lineMetricUpdateEpoch += 1;
	if (action == TK_TEXT_INVALIDATE_DELETE) {
7202
7203
7204
7205
7206
7207
7208
7209
7210
7211
7212
7213
7214
7215
7216
	if (displayLineOffset > 0) {
	    ComputeMissingMetric(textPtr, &info, THRESHOLD_LINE_OFFSET, displayLineOffset);
	    info.numDispLines -= info.displayLineNo;

	    while (true) {
		const TkTextDispLineEntry *last;

		if (info.numDispLines >= displayLineOffset) {
		    last = info.entry + displayLineOffset;
		    byteOffset = last->byteOffset;
		    break;
		}
		last = info.entry + info.numDispLines;
		byteOffset = last->byteOffset;
		displayLineOffset -= info.numDispLines;







|







7218
7219
7220
7221
7222
7223
7224
7225
7226
7227
7228
7229
7230
7231
7232
	if (displayLineOffset > 0) {
	    ComputeMissingMetric(textPtr, &info, THRESHOLD_LINE_OFFSET, displayLineOffset);
	    info.numDispLines -= info.displayLineNo;

	    while (true) {
		const TkTextDispLineEntry *last;

		if ((int) info.numDispLines >= displayLineOffset) {
		    last = info.entry + displayLineOffset;
		    byteOffset = last->byteOffset;
		    break;
		}
		last = info.entry + info.numDispLines;
		byteOffset = last->byteOffset;
		displayLineOffset -= info.numDispLines;
7226
7227
7228
7229
7230
7231
7232
7233
7234
7235
7236
7237
7238
7239
7240
7241
7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
	    }
	} else if (displayLineOffset < 0) {
	    info.numDispLines = info.displayLineNo + 1;

	    while (true) {
		TkTextLine *prevLine;

		if (-displayLineOffset < info.numDispLines) {
		    int skipBack;

		    byteOffset = (info.entry + displayLineOffset)->byteOffset;
		    skipBack = displayLineOffset;

		    /*
		     * We want to cache this display line, because it's likely that this
		     * line will be used afterwards. Take into account that probably the
		     * last cached line has been removed.
		     */

		    if ((skipBack -= removedLines) >= 0 && info.numCachedLines > skipBack) {
			DLine *dlPtr = info.lastDLinePtr;
			while (dlPtr && skipBack--) {
			    dlPtr = dlPtr->prevPtr;
			}
			if (dlPtr == info.dLinePtr) {
			    info.dLinePtr = dlPtr->nextPtr;
			}







|











|







7242
7243
7244
7245
7246
7247
7248
7249
7250
7251
7252
7253
7254
7255
7256
7257
7258
7259
7260
7261
7262
7263
7264
7265
7266
7267
7268
	    }
	} else if (displayLineOffset < 0) {
	    info.numDispLines = info.displayLineNo + 1;

	    while (true) {
		TkTextLine *prevLine;

		if (-displayLineOffset < (int) info.numDispLines) {
		    int skipBack;

		    byteOffset = (info.entry + displayLineOffset)->byteOffset;
		    skipBack = displayLineOffset;

		    /*
		     * We want to cache this display line, because it's likely that this
		     * line will be used afterwards. Take into account that probably the
		     * last cached line has been removed.
		     */

		    if ((skipBack -= removedLines) >= 0 && (int) info.numCachedLines > skipBack) {
			DLine *dlPtr = info.lastDLinePtr;
			while (dlPtr && skipBack--) {
			    dlPtr = dlPtr->prevPtr;
			}
			if (dlPtr == info.dLinePtr) {
			    info.dLinePtr = dlPtr->nextPtr;
			}
7481
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
 *
 *	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 'numLogicalLinesMergedPtr' 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!
 *
 *----------------------------------------------------------------------
 */

#if !NDEBUG
static bool
IsAtStartOfDisplayLine(
    const TkTextIndex *indexPtr)
{
    TkTextIndex index2 = *indexPtr;

    assert(indexPtr->textPtr);

    FindDisplayLineStartEnd(indexPtr->textPtr, &index2, DISP_LINE_START, DLINE_METRIC);
    return TkTextIndexCompare(&index2, indexPtr) == 0;
}
#endif

static int
CalculateDisplayLineHeight(
    TkText *textPtr,		/* Widget record for text widget. */
    const TkTextIndex *indexPtr,/* The index at the beginning of the display line of interest. */
    unsigned *byteCountRef)	/* NULL or used to return the number of byte indices on the given
    				 * display line. */







|



<
<
<

|
<
<
<
<




|











|







7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507



7508
7509




7510
7511
7512
7513
7514
7515
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527
7528
7529
7530
7531
7532
7533
 *
 *	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 'byteCountRef' 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).
 *



 * Side effects:
 *	The same as LayoutDLine and FreeDLines.




 *
 *----------------------------------------------------------------------
 */

#ifndef NDEBUG
static bool
IsAtStartOfDisplayLine(
    const TkTextIndex *indexPtr)
{
    TkTextIndex index2 = *indexPtr;

    assert(indexPtr->textPtr);

    FindDisplayLineStartEnd(indexPtr->textPtr, &index2, DISP_LINE_START, DLINE_METRIC);
    return TkTextIndexCompare(&index2, indexPtr) == 0;
}
#endif /* NDEBUG */

static int
CalculateDisplayLineHeight(
    TkText *textPtr,		/* Widget record for text widget. */
    const TkTextIndex *indexPtr,/* The index at the beginning of the display line of interest. */
    unsigned *byteCountRef)	/* NULL or used to return the number of byte indices on the given
    				 * display line. */
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
    return TkBTreePixelsTo(textPtr, TkTextIndexGetLine(indexPtr)) +
	    GetPixelsTo(textPtr, indexPtr, false, NULL);
}

/*
 *----------------------------------------------------------------------
 *
 * 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







|







7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
    return TkBTreePixelsTo(textPtr, TkTextIndexGetLine(indexPtr)) +
	    GetPixelsTo(textPtr, indexPtr, false, NULL);
}

/*
 *----------------------------------------------------------------------
 *
 * UpdateOneLine --
 *
 *	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
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
 *	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. */
    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. */
    unsigned maxDispLines)	/* Don't compute more than this number of display lines. */







|
|







7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
7748
7749
 *	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.
 *
 *----------------------------------------------------------------------
 */

static int
UpdateOneLine(
    TkText *textPtr,		/* Widget record for text widget. */
    TkTextLine *linePtr,	/* The line of which to calculate the height. */
    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. */
    unsigned maxDispLines)	/* Don't compute more than this number of display lines. */
7774
7775
7776
7777
7778
7779
7780
7781
7782
7783
7784
7785
7786
7787
7788
	TkTextIndexForwBytes(textPtr, indexPtr, bytes, indexPtr);
	linePtr = TkTextIndexGetLine(indexPtr);
	assert(!linePtr->logicalLine || !TkTextIndexIsStartOfLine(indexPtr));
    } else if (!linePtr->logicalLine || !TkTextIndexIsStartOfLine(indexPtr)) {
	/*
	 * CalculateDisplayLineHeight must be called 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.
	 */








|







7783
7784
7785
7786
7787
7788
7789
7790
7791
7792
7793
7794
7795
7796
7797
	TkTextIndexForwBytes(textPtr, indexPtr, bytes, indexPtr);
	linePtr = TkTextIndexGetLine(indexPtr);
	assert(!linePtr->logicalLine || !TkTextIndexIsStartOfLine(indexPtr));
    } else if (!linePtr->logicalLine || !TkTextIndexIsStartOfLine(indexPtr)) {
	/*
	 * CalculateDisplayLineHeight must be called with an index at the beginning
	 * of a display line. Force this to happen. This is needed when
	 * UpdateOneLine 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.
	 */

8931
8932
8933
8934
8935
8936
8937
8938
8939
8940
8941
8942
8943
8944
8945
8946
{
    TkSharedText *sharedTextPtr = textPtr->sharedTextPtr;
    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
    XGCValues gcValues;
    GC newGC;
    bool recomputeGeometry;
    bool asyncLineCalculation;
    int firstLineNo;
    int lastLineNo;
    int maxX;

    if ((mask & TK_TEXT_LINE_REDRAW_BOTTOM_LINE) && dInfoPtr->lastDLinePtr) {
	dInfoPtr->lastDLinePtr->flags |= OLD_Y_INVALID;
    }

    /*







|
|







8940
8941
8942
8943
8944
8945
8946
8947
8948
8949
8950
8951
8952
8953
8954
8955
{
    TkSharedText *sharedTextPtr = textPtr->sharedTextPtr;
    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
    XGCValues gcValues;
    GC newGC;
    bool recomputeGeometry;
    bool asyncLineCalculation;
    unsigned firstLineNo;
    unsigned lastLineNo;
    int maxX;

    if ((mask & TK_TEXT_LINE_REDRAW_BOTTOM_LINE) && dInfoPtr->lastDLinePtr) {
	dInfoPtr->lastDLinePtr->flags |= OLD_Y_INVALID;
    }

    /*
9715
9716
9717
9718
9719
9720
9721
9722

9723
9724
9725
9726
9727
9728
9729
    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;
    }







|
>







9724
9725
9726
9727
9728
9729
9730
9731
9732
9733
9734
9735
9736
9737
9738
9739
    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, oneThird, delta;
    unsigned lineWidth, byteCount;
    DLine *dlPtr;
    TkTextDispChunk *chunkPtr;

    if (objc != 3) {
	Tcl_WrongNumArgs(interp, 2, objv, "index");
	return TCL_ERROR;
    }
9752
9753
9754
9755
9756
9757
9758


9759

9760
9761
9762
9763
9764
9765
9766
    /*
     * 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;
    }

    /*
     * Take into account that the desired index is past the visible text.
     * It's also possible that the widget is not yet mapped.







>
>

>







9762
9763
9764
9765
9766
9767
9768
9769
9770
9771
9772
9773
9774
9775
9776
9777
9778
9779
    /*
     * Now make sure that the character is in view horizontally.
     */

    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
	UpdateDisplayInfo(textPtr);
    }

    assert(dInfoPtr->maxX >= dInfoPtr->x);
    lineWidth = dInfoPtr->maxX - dInfoPtr->x;

    if (dInfoPtr->maxLength < lineWidth) {
	return TCL_OK;
    }

    /*
     * Take into account that the desired index is past the visible text.
     * It's also possible that the widget is not yet mapped.
11489
11490
11491
11492
11493
11494
11495
11496
11497
11498
11499
11500
11501
11502
11503
 *----------------------------------------------------------------------
 */

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. */
{
    TkTextDispChunkSection *sectionPtr, *nextPtr;
    TkTextDispChunk *chunkPtr;
    int x;

    if (byteIndex == 0 || !(sectionPtr = dlPtr->chunkPtr->sectionPtr)) {
	return 0;







|







11502
11503
11504
11505
11506
11507
11508
11509
11510
11511
11512
11513
11514
11515
11516
 *----------------------------------------------------------------------
 */

static int
DLineXOfIndex(
    TkText *textPtr,		/* Widget record for text widget. */
    DLine *dlPtr,		/* Display information for this display line. */
    unsigned byteIndex)		/* The byte index for which we want the coordinate. */
{
    TkTextDispChunkSection *sectionPtr, *nextPtr;
    TkTextDispChunk *chunkPtr;
    int x;

    if (byteIndex == 0 || !(sectionPtr = dlPtr->chunkPtr->sectionPtr)) {
	return 0;
11571
11572
11573
11574
11575
11576
11577
11578
11579
11580
11581
11582
11583
11584
11585
    				 * 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;
    TkTextDispChunk *chunkPtr;
    TkTextDispChunkSection *sectionPtr;
    int byteCount;

    /*
     * Make sure that all of the screen layout information is up to date.
     */

    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
	UpdateDisplayInfo(textPtr);







|







11584
11585
11586
11587
11588
11589
11590
11591
11592
11593
11594
11595
11596
11597
11598
    				 * 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;
    TkTextDispChunk *chunkPtr;
    TkTextDispChunkSection *sectionPtr;
    unsigned byteCount;

    /*
     * Make sure that all of the screen layout information is up to date.
     */

    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
	UpdateDisplayInfo(textPtr);
12134
12135
12136
12137
12138
12139
12140
12141

12142
12143
12144
12145
12146
12147
12148

static void
ComputeSizeOfTab(
    LayoutData *data)
{
    TkText *textPtr;
    TkTextTabArray *tabArrayPtr;
    unsigned tabX, tabWidth;

    TkTextTabAlign alignment;

    textPtr = data->textPtr;
    tabArrayPtr = data->tabArrayPtr;

    if (!tabArrayPtr || tabArrayPtr->numTabs == 0) {
	/*







|
>







12147
12148
12149
12150
12151
12152
12153
12154
12155
12156
12157
12158
12159
12160
12161
12162

static void
ComputeSizeOfTab(
    LayoutData *data)
{
    TkText *textPtr;
    TkTextTabArray *tabArrayPtr;
    unsigned tabWidth;
    int tabX;
    TkTextTabAlign alignment;

    textPtr = data->textPtr;
    tabArrayPtr = data->tabArrayPtr;

    if (!tabArrayPtr || tabArrayPtr->numTabs == 0) {
	/*
12609
12610
12611
12612
12613
12614
12615
12616
12617
12618
12619
12620
12621
12622
12623
	const char *p;
	int count;

	if (segPtr->typePtr == &tkTextHyphenType) {
	    return 1;
	}

	if (chunkPtr->numBytes + byteOffset == segPtr->size) {
	    for (nextPtr = segPtr->nextPtr; nextPtr; nextPtr = nextPtr->nextPtr) {
		if (nextPtr->size > 0) {
		    if (!(nextPtr->typePtr->group & (SEG_GROUP_CHAR|SEG_GROUP_HYPHEN))) {
			return chunkPtr->numBytes;
		    }
		    break;
		} else if (nextPtr->typePtr == &tkTextBranchType) {







|







12623
12624
12625
12626
12627
12628
12629
12630
12631
12632
12633
12634
12635
12636
12637
	const char *p;
	int count;

	if (segPtr->typePtr == &tkTextHyphenType) {
	    return 1;
	}

	if ((int) chunkPtr->numBytes + byteOffset == segPtr->size) {
	    for (nextPtr = segPtr->nextPtr; nextPtr; nextPtr = nextPtr->nextPtr) {
		if (nextPtr->size > 0) {
		    if (!(nextPtr->typePtr->group & (SEG_GROUP_CHAR|SEG_GROUP_HYPHEN))) {
			return chunkPtr->numBytes;
		    }
		    break;
		} else if (nextPtr->typePtr == &tkTextBranchType) {
13144
13145
13146
13147
13148
13149
13150
13151
13152
13153
13154
13155
13156
13157
13158
13159
13160
13161
13162
13163
13164
13165
13166
13167
13168
13169
13170
13171
13172
	     * At least one character should be contained in current display line.
	     */

	    bytesThatFit = CharChunkMeasureChars(chunkPtr, ciPtr->u.chars, ciPtr->baseOffset + chLen,
		    ciPtr->baseOffset, -1, chunkPtr->x, -1, 0, &nextX);
	}
	if (spaceMode == TEXT_SPACEMODE_TRIM) {
	    while (isblank(p[bytesThatFit])) {
		bytesThatFit += 1;
	    }
	}
	if (p[bytesThatFit] == '\n') {
	    /*
	     * A newline character takes up no space, so if the previous
	     * character fits then so does the newline.
	     */

	    bytesThatFit += 1;
	} else if (spaceMode == TEXT_SPACEMODE_NONE
		&& nextX <= maxX
		&& ((1 << wrapMode) & ((1 << TEXT_WRAPMODE_WORD) | (1 << TEXT_WRAPMODE_CODEPOINT)))
		&& isblank(p[bytesThatFit])
		&& !(bytesThatFit == 0
		    && chunkPtr->prevCharChunkPtr
		    && chunkPtr->prevCharChunkPtr->wrappedAtSpace)) {
	    /*
	     * Space characters are funny, in that they are considered to fit at the end
	     * of the line. Just give the space character whatever space is left.
	     */







|













|







13158
13159
13160
13161
13162
13163
13164
13165
13166
13167
13168
13169
13170
13171
13172
13173
13174
13175
13176
13177
13178
13179
13180
13181
13182
13183
13184
13185
13186
	     * At least one character should be contained in current display line.
	     */

	    bytesThatFit = CharChunkMeasureChars(chunkPtr, ciPtr->u.chars, ciPtr->baseOffset + chLen,
		    ciPtr->baseOffset, -1, chunkPtr->x, -1, 0, &nextX);
	}
	if (spaceMode == TEXT_SPACEMODE_TRIM) {
	    while (IsBlank(p[bytesThatFit])) {
		bytesThatFit += 1;
	    }
	}
	if (p[bytesThatFit] == '\n') {
	    /*
	     * A newline character takes up no space, so if the previous
	     * character fits then so does the newline.
	     */

	    bytesThatFit += 1;
	} else if (spaceMode == TEXT_SPACEMODE_NONE
		&& nextX <= maxX
		&& ((1 << wrapMode) & ((1 << TEXT_WRAPMODE_WORD) | (1 << TEXT_WRAPMODE_CODEPOINT)))
		&& IsBlank(p[bytesThatFit])
		&& !(bytesThatFit == 0
		    && chunkPtr->prevCharChunkPtr
		    && chunkPtr->prevCharChunkPtr->wrappedAtSpace)) {
	    /*
	     * Space characters are funny, in that they are considered to fit at the end
	     * of the line. Just give the space character whatever space is left.
	     */

Changes to generic/tkTextImage.c.

13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#include "tkPort.h"
#include "tkText.h"
#include "tkTextTagSet.h"
#include "tkTextUndo.h"
#include <assert.h>

#ifndef MIN
# define MIN(a,b) ((a) < (b) ? a : b)
#endif
#ifndef MAX
# define MAX(a,b) ((a) < (b) ? b : a)
#endif

#if NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Support of tk8.5.







<
<
<
<
<
<
<
|







13
14
15
16
17
18
19







20
21
22
23
24
25
26
27

#include "tkPort.h"
#include "tkText.h"
#include "tkTextTagSet.h"
#include "tkTextUndo.h"
#include <assert.h>








#ifdef NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Support of tk8.5.
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
 */

static bool
Displayed(
    const TkTextEmbImage *img,
    const TkText *peer)
{
    return peer->pixelReference < img->numClients
	    && !TkQTreeRectIsEmpty(&img->bbox[peer->pixelReference]);
}

int
TkTextImageCmd(
    TkText *textPtr,		/* Information about text widget. */
    Tcl_Interp *interp,		/* Current interpreter. */







|







346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
 */

static bool
Displayed(
    const TkTextEmbImage *img,
    const TkText *peer)
{
    return peer->pixelReference < (int) img->numClients
	    && !TkQTreeRectIsEmpty(&img->bbox[peer->pixelReference]);
}

int
TkTextImageCmd(
    TkText *textPtr,		/* Information about text widget. */
    Tcl_Interp *interp,		/* Current interpreter. */
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645

    for (hPtr = Tcl_FirstHashEntry(&sharedTextPtr->imageTable, &search);
	    hPtr;
	    hPtr = Tcl_NextHashEntry(&search)) {
	TkTextSegment *eiPtr = Tcl_GetHashValue(hPtr);
	TkTextEmbImage *img = &eiPtr->body.ei;

	if (img->numClients > textPtr->pixelReference) {
	    memset(&img->bbox[textPtr->pixelReference], 0, sizeof(img->bbox[0]));
	}
    }
}

/*
 *--------------------------------------------------------------







|







624
625
626
627
628
629
630
631
632
633
634
635
636
637
638

    for (hPtr = Tcl_FirstHashEntry(&sharedTextPtr->imageTable, &search);
	    hPtr;
	    hPtr = Tcl_NextHashEntry(&search)) {
	TkTextSegment *eiPtr = Tcl_GetHashValue(hPtr);
	TkTextEmbImage *img = &eiPtr->body.ei;

	if ((int) img->numClients > textPtr->pixelReference) {
	    memset(&img->bbox[textPtr->pixelReference], 0, sizeof(img->bbox[0]));
	}
    }
}

/*
 *--------------------------------------------------------------
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
	 */

	TkQTreeRectSet(&bbox, dx, dy, Tk_Width(textPtr->tkwin) + dx, Tk_Height(textPtr->tkwin) + dy);
	TkQTreeConfigure(&textPtr->imageBboxTree, &bbox);
	textPtr->configureBboxTree = false;
    }

    if (img->numClients <= textPtr->pixelReference) {
	unsigned numClients = textPtr->pixelReference + 1;

	assert((img->numClients == 0) == !img->bbox);
	img->bbox = realloc(img->bbox, numClients * sizeof(img->bbox[0]));
	memset(img->bbox + img->numClients, 0, (numClients - img->numClients) * sizeof(img->bbox[0]));
	img->numClients = numClients;
    }







|







1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
	 */

	TkQTreeRectSet(&bbox, dx, dy, Tk_Width(textPtr->tkwin) + dx, Tk_Height(textPtr->tkwin) + dy);
	TkQTreeConfigure(&textPtr->imageBboxTree, &bbox);
	textPtr->configureBboxTree = false;
    }

    if ((int) img->numClients <= textPtr->pixelReference) {
	unsigned numClients = textPtr->pixelReference + 1;

	assert((img->numClients == 0) == !img->bbox);
	img->bbox = realloc(img->bbox, numClients * sizeof(img->bbox[0]));
	memset(img->bbox + img->numClients, 0, (numClients - img->numClients) * sizeof(img->bbox[0]));
	img->numClients = numClients;
    }

Changes to generic/tkTextIndex.c.

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef MAX
# define MAX(a,b) (((int) a) < ((int) b) ? b : a)
#endif
#ifndef MIN
# define MIN(a,b) (((int) a) < ((int) b) ? a : b)
#endif

#if NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Modifiers for index parsing: 'display', 'any' or nothing.







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#ifndef MAX
# define MAX(a,b) (((int) a) < ((int) b) ? b : a)
#endif
#ifndef MIN
# define MIN(a,b) (((int) a) < ((int) b) ? a : b)
#endif

#ifdef NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Modifiers for index parsing: 'display', 'any' or nothing.
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#if !NDEBUG
static bool
CheckLine(
    const TkTextIndex *indexPtr,
    const TkTextLine *linePtr)
{
    assert(linePtr);

    if (indexPtr->stateEpoch == TkBTreeEpoch(indexPtr->tree)) {
	if (indexPtr->priv.segPtr
		&& indexPtr->priv.segPtr->sectionPtr->linePtr != indexPtr->priv.linePtr) {
	    return false;
	}
	if (indexPtr->priv.lineNo != -1
		&& indexPtr->priv.lineNo !=
		    TkBTreeLinesTo(indexPtr->tree, NULL, indexPtr->priv.linePtr, NULL)) {
	    return false;
	}
	if (indexPtr->priv.lineNoRel != -1
		&& indexPtr->priv.lineNoRel !=
		    TkBTreeLinesTo(indexPtr->tree, indexPtr->textPtr, indexPtr->priv.linePtr, NULL)) {
	    return false;
	}
    }

    if (!indexPtr->discardConsistencyCheck && indexPtr->textPtr) {
	const TkTextLine *startLine = TkBTreeGetStartLine(indexPtr->textPtr);
	const TkTextLine *endLine = TkBTreeGetLastLine(indexPtr->textPtr);
	int lineNo = TkBTreeLinesTo(indexPtr->tree, NULL, linePtr, NULL);

	if (lineNo < TkBTreeLinesTo(indexPtr->tree, NULL, startLine, NULL)) {
	    return false;
	}
	if (lineNo > TkBTreeLinesTo(indexPtr->tree, NULL, endLine, NULL)) {
	    return false;
	}
    }

    return true;
}
#endif

static int
FindStartByteIndex(
    const TkTextIndex *indexPtr)
{
    const TkText *textPtr = indexPtr->textPtr;
    const TkTextSegment *segPtr;







|














|




|









|


|






|







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#ifndef NDEBUG
static bool
CheckLine(
    const TkTextIndex *indexPtr,
    const TkTextLine *linePtr)
{
    assert(linePtr);

    if (indexPtr->stateEpoch == TkBTreeEpoch(indexPtr->tree)) {
	if (indexPtr->priv.segPtr
		&& indexPtr->priv.segPtr->sectionPtr->linePtr != indexPtr->priv.linePtr) {
	    return false;
	}
	if (indexPtr->priv.lineNo != -1
		&& indexPtr->priv.lineNo !=
		(int) TkBTreeLinesTo(indexPtr->tree, NULL, indexPtr->priv.linePtr, NULL)) {
	    return false;
	}
	if (indexPtr->priv.lineNoRel != -1
		&& indexPtr->priv.lineNoRel !=
		(int) TkBTreeLinesTo(indexPtr->tree, indexPtr->textPtr, indexPtr->priv.linePtr, NULL)) {
	    return false;
	}
    }

    if (!indexPtr->discardConsistencyCheck && indexPtr->textPtr) {
	const TkTextLine *startLine = TkBTreeGetStartLine(indexPtr->textPtr);
	const TkTextLine *endLine = TkBTreeGetLastLine(indexPtr->textPtr);
	int lineNo = TkBTreeLinesTo(indexPtr->tree, NULL, linePtr, NULL);

	if (lineNo < (int) TkBTreeLinesTo(indexPtr->tree, NULL, startLine, NULL)) {
	    return false;
	}
	if (lineNo > (int) TkBTreeLinesTo(indexPtr->tree, NULL, endLine, NULL)) {
	    return false;
	}
    }

    return true;
}
#endif /* NDEBUG */

static int
FindStartByteIndex(
    const TkTextIndex *indexPtr)
{
    const TkText *textPtr = indexPtr->textPtr;
    const TkTextSegment *segPtr;
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#if !NDEBUG
static bool
CheckByteIndex(
    const TkTextIndex *indexPtr,
    const TkTextLine *linePtr,
    int byteIndex)
{
    const TkText *textPtr = indexPtr->textPtr;







|







275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
 *
 * Side effects:
 *	None.
 *
 *----------------------------------------------------------------------
 */

#ifndef NDEBUG
static bool
CheckByteIndex(
    const TkTextIndex *indexPtr,
    const TkTextLine *linePtr,
    int byteIndex)
{
    const TkText *textPtr = indexPtr->textPtr;
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
	if (linePtr == textPtr->endMarker->sectionPtr->linePtr->nextPtr) {
	    return byteIndex == 0;
	}
    }

    return byteIndex < linePtr->size;
}
#endif /* !NDEBUG */

void
TkTextIndexSetPosition(
    TkTextIndex *indexPtr,	/* Pointer to index. */
    int byteIndex,		/* New byte index. */
    TkTextSegment *segPtr)	/* The segment which belongs to the byte index. */
{







|







306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
	if (linePtr == textPtr->endMarker->sectionPtr->linePtr->nextPtr) {
	    return byteIndex == 0;
	}
    }

    return byteIndex < linePtr->size;
}
#endif /* NDEBUG */

void
TkTextIndexSetPosition(
    TkTextIndex *indexPtr,	/* Pointer to index. */
    int byteIndex,		/* New byte index. */
    TkTextSegment *segPtr)	/* The segment which belongs to the byte index. */
{
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
    indexPtr->priv.linePtr = segPtr->sectionPtr->linePtr;
    indexPtr->priv.byteIndex = byteIndex;
    indexPtr->priv.lineNo = -1;
    indexPtr->priv.lineNoRel = -1;
    indexPtr->priv.segPtr = segPtr;
    indexPtr->priv.isCharSegment = segPtr->typePtr == &tkTextCharType;

#if !NDEBUG
    {
	int pos = SegToIndex(indexPtr->priv.linePtr, segPtr);

	if (segPtr->typePtr == &tkTextCharType) {
	    assert(byteIndex - pos < segPtr->size);
	} else {
	    assert(pos == byteIndex);
	}
    }
#endif /* !NDEBUG */
}

/*
 *----------------------------------------------------------------------
 *
 * TkTextIndexSetByteIndex --
 *







|









|







330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
    indexPtr->priv.linePtr = segPtr->sectionPtr->linePtr;
    indexPtr->priv.byteIndex = byteIndex;
    indexPtr->priv.lineNo = -1;
    indexPtr->priv.lineNoRel = -1;
    indexPtr->priv.segPtr = segPtr;
    indexPtr->priv.isCharSegment = segPtr->typePtr == &tkTextCharType;

#ifndef NDEBUG
    {
	int pos = SegToIndex(indexPtr->priv.linePtr, segPtr);

	if (segPtr->typePtr == &tkTextCharType) {
	    assert(byteIndex - pos < segPtr->size);
	} else {
	    assert(pos == byteIndex);
	}
    }
#endif /* NDEBUG */
}

/*
 *----------------------------------------------------------------------
 *
 * TkTextIndexSetByteIndex --
 *
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
	    assert(!iPtr->priv.isCharSegment || indexPtr->stateEpoch == epoch);
	    iPtr->priv.byteIndex = SegToIndex(iPtr->priv.linePtr, iPtr->priv.segPtr);
	    assert(CheckByteIndex(iPtr, iPtr->priv.linePtr, iPtr->priv.byteIndex));
	}
	TkTextIndexSetEpoch(iPtr, epoch);
	*lineNo = TkBTreeLinesTo(iPtr->tree, textPtr, iPtr->priv.linePtr, NULL);
    } else {
	assert(*lineNo == TkBTreeLinesTo(indexPtr->tree, textPtr, indexPtr->priv.linePtr, NULL));
    }

    return *lineNo;
}

/*
 *----------------------------------------------------------------------







|







908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
	    assert(!iPtr->priv.isCharSegment || indexPtr->stateEpoch == epoch);
	    iPtr->priv.byteIndex = SegToIndex(iPtr->priv.linePtr, iPtr->priv.segPtr);
	    assert(CheckByteIndex(iPtr, iPtr->priv.linePtr, iPtr->priv.byteIndex));
	}
	TkTextIndexSetEpoch(iPtr, epoch);
	*lineNo = TkBTreeLinesTo(iPtr->tree, textPtr, iPtr->priv.linePtr, NULL);
    } else {
	assert(*lineNo == (int) TkBTreeLinesTo(indexPtr->tree, textPtr, indexPtr->priv.linePtr, NULL));
    }

    return *lineNo;
}

/*
 *----------------------------------------------------------------------
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
 *	None.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
#if !NDEBUG

void
TkpTextIndexDump(
    TkText *textPtr,		/* May be NULL. */
    const TkTextIndex *indexPtr)/* Pointer to index. */
{
    char buf[TK_POS_CHARS];
    TkTextIndexPrint(TkTextIndexGetShared(indexPtr), textPtr, indexPtr, buf);
    printf("%s\n", buf);
}

#endif /* !NDEBUG */

/*
 *---------------------------------------------------------------------------
 *
 * TkTextNewIndexObj --
 *
 *	This function generates a Tcl_Obj description of an index, suitable







|











|







1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
 *	None.
 *
 * Side effects:
 *	None.
 *
 *---------------------------------------------------------------------------
 */
#ifndef NDEBUG

void
TkpTextIndexDump(
    TkText *textPtr,		/* May be NULL. */
    const TkTextIndex *indexPtr)/* Pointer to index. */
{
    char buf[TK_POS_CHARS];
    TkTextIndexPrint(TkTextIndexGetShared(indexPtr), textPtr, indexPtr, buf);
    printf("%s\n", buf);
}

#endif /* NDEBUG */

/*
 *---------------------------------------------------------------------------
 *
 * TkTextNewIndexObj --
 *
 *	This function generates a Tcl_Obj description of an index, suitable
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
    } else if (!linePtr->nextPtr) {
	return 1;
    }

    if ((byteIndex = dstPtr->priv.byteIndex + byteCount) > linePtr->size) {
	DEBUG(TkTextIndex index = *srcPtr);
	bool rc = TkBTreeMoveForward(dstPtr, byteCount);
	assert(!rc || TkTextIndexCountBytes(&index, dstPtr) == byteCount);
	return rc ? 0 : 1;
    }

    if (byteIndex == linePtr->size) {
	assert(linePtr->nextPtr);
	TkTextIndexSetByteIndex2(dstPtr, linePtr->nextPtr, 0);
    } else {







|







2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
    } else if (!linePtr->nextPtr) {
	return 1;
    }

    if ((byteIndex = dstPtr->priv.byteIndex + byteCount) > linePtr->size) {
	DEBUG(TkTextIndex index = *srcPtr);
	bool rc = TkBTreeMoveForward(dstPtr, byteCount);
	assert(!rc || (int) TkTextIndexCountBytes(&index, dstPtr) == byteCount);
	return rc ? 0 : 1;
    }

    if (byteIndex == linePtr->size) {
	assert(linePtr->nextPtr);
	TkTextIndexSetByteIndex2(dstPtr, linePtr->nextPtr, 0);
    } else {
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
	TkTextIndexSetByteIndex(dstPtr, byteIndex);
	return 0;
    }

    if (byteCount > byteIndex + 1) {
	DEBUG(TkTextIndex index = *srcPtr);
	bool rc = TkBTreeMoveBackward(dstPtr, byteCount);
	assert(!rc || TkTextIndexCountBytes(dstPtr, &index) == byteCount);
	return rc ? 0 : 1;
    }

    if ((byteIndex -= byteCount) >= 0) {
	TkTextIndexSetByteIndex(dstPtr, byteIndex);
	return 0;
    }







|







3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
	TkTextIndexSetByteIndex(dstPtr, byteIndex);
	return 0;
    }

    if (byteCount > byteIndex + 1) {
	DEBUG(TkTextIndex index = *srcPtr);
	bool rc = TkBTreeMoveBackward(dstPtr, byteCount);
	assert(!rc || (int) TkTextIndexCountBytes(dstPtr, &index) == byteCount);
	return rc ? 0 : 1;
    }

    if ((byteIndex -= byteCount) >= 0) {
	TkTextIndexSetByteIndex(dstPtr, byteIndex);
	return 0;
    }

Changes to generic/tkTextLineBreak.c.

244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
	    } else if (text[i] == '/' && i > 8) {
		/*
		 * Ignore the breaking chance if there is a chance immediately before:
		 * no break inside "c/o", and no break after "http://" in a long line
		 * (a suggestion from Wu Yongwei).
		 */

		if (lastBreakablePos >= i - 2
			|| (i > 40 && lastBreakablePos >= i - 7 && text[i - 1] == '/')) {
		    continue;
		}

		/*
		 * Special rule to treat Unix paths more nicely (a suggestion from Wu Yongwei).
		 */








|
|







244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
	    } else if (text[i] == '/' && i > 8) {
		/*
		 * Ignore the breaking chance if there is a chance immediately before:
		 * no break inside "c/o", and no break after "http://" in a long line
		 * (a suggestion from Wu Yongwei).
		 */

		if (lastBreakablePos >= (int) i - 2
			|| (i > 40u && lastBreakablePos >= (int) i - 7 && text[i - 1] == '/')) {
		    continue;
		}

		/*
		 * Special rule to treat Unix paths more nicely (a suggestion from Wu Yongwei).
		 */

887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
	    /*
	     * This fallback is required, because ths current character conversion
	     * algorithm in Tcl library is producing overlong sequences (a violation
	     * of the UTF-8 standard). This observation has been reported to the
	     * Tcl/Tk team, but the response was ignorance.
	     */

	    int k;
	    const char *p = (const char *) text + i;

	    pcls = AI;
	    nbytes = Tcl_UtfNext(p) - p;
	    for (k = 0; k < nbytes; ++k) {
		brks[i + k] = LINEBREAK_INSIDEACHAR;
	    }







|







887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
	    /*
	     * This fallback is required, because ths current character conversion
	     * algorithm in Tcl library is producing overlong sequences (a violation
	     * of the UTF-8 standard). This observation has been reported to the
	     * Tcl/Tk team, but the response was ignorance.
	     */

	    unsigned k;
	    const char *p = (const char *) text + i;

	    pcls = AI;
	    nbytes = Tcl_UtfNext(p) - p;
	    for (k = 0; k < nbytes; ++k) {
		brks[i + k] = LINEBREAK_INSIDEACHAR;
	    }

Changes to generic/tkTextMark.c.

11
12
13
14
15
16
17



18




19




20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 * 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"
#include "tk3d.h"



#include <inttypes.h>




#include <assert.h>





#ifndef MAX
# define MAX(a,b) ((a) < (b) ? b : a)
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? a : b)
#endif

#if NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Forward references for functions defined in this file:







>
>
>
|
>
>
>
>
|
>
>
>
>








|







11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 * 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"
#include "tk3d.h"
#include <assert.h>

#if HAVE_INTTYPES_H
# include <inttypes.h>
#elif !defined(PRIx32)
# define PRIx64 "llx"
# define PRIx32 "lx"
#endif

#ifdef MSC_VER
/* earlier versions of MSCV don't knows snprintf, but _snprintf is compatible. */
# define snprintf _snprintf
#endif

#ifndef MAX
# define MAX(a,b) ((a) < (b) ? b : a)
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? a : b)
#endif

#ifdef NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Forward references for functions defined in this file:
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247

#define GET_POINTER(ptr)	((void *) (((__ptr_to_int *) &ptr)->flag & ~(uintptr_t) 1))

#define GET_NAME(seg)		((char *) GET_POINTER(seg->body.mark.ptr))
#define GET_HPTR(seg)		((Tcl_HashEntry *) seg->body.mark.ptr)
#define PTR_TO_INT(ptr)		((uintptr_t) ptr)

#if !NDEBUG

# undef GET_HPTR
# undef GET_NAME

static Tcl_HashEntry *GET_HPTR(const TkTextSegment *markPtr)
{ assert(!IS_PRESERVED(markPtr)); return (Tcl_HashEntry *) markPtr->body.mark.ptr; }

static char *GET_NAME(const TkTextSegment *markPtr)
{ assert(IS_PRESERVED(markPtr)); return (char *) GET_POINTER(markPtr->body.mark.ptr); }

#endif /* !NDEBUG */

DEBUG_ALLOC(extern unsigned tkTextCountNewSegment);
DEBUG_ALLOC(extern unsigned tkTextCountDestroySegment);
DEBUG_ALLOC(extern unsigned tkTextCountNewUndoToken);
DEBUG_ALLOC(extern unsigned tkTextCountDestroyUndoToken);

/*







|










|







233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

#define GET_POINTER(ptr)	((void *) (((__ptr_to_int *) &ptr)->flag & ~(uintptr_t) 1))

#define GET_NAME(seg)		((char *) GET_POINTER(seg->body.mark.ptr))
#define GET_HPTR(seg)		((Tcl_HashEntry *) seg->body.mark.ptr)
#define PTR_TO_INT(ptr)		((uintptr_t) ptr)

#ifndef NDEBUG

# undef GET_HPTR
# undef GET_NAME

static Tcl_HashEntry *GET_HPTR(const TkTextSegment *markPtr)
{ assert(!IS_PRESERVED(markPtr)); return (Tcl_HashEntry *) markPtr->body.mark.ptr; }

static char *GET_NAME(const TkTextSegment *markPtr)
{ assert(IS_PRESERVED(markPtr)); return (char *) GET_POINTER(markPtr->body.mark.ptr); }

#endif /* NDEBUG */

DEBUG_ALLOC(extern unsigned tkTextCountNewSegment);
DEBUG_ALLOC(extern unsigned tkTextCountDestroySegment);
DEBUG_ALLOC(extern unsigned tkTextCountNewUndoToken);
DEBUG_ALLOC(extern unsigned tkTextCountDestroyUndoToken);

/*
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
	hPtr = Tcl_CreateHashEntry(&sharedTextPtr->markTable, name, &dummy);
	markPtr = Tcl_GetHashValue(hPtr);
    }

    if (!markPtr) {
	if (name[0] == '#' && name[1] == '#' && name[2] == 'I') {
#ifdef TCL_WIDE_INT_IS_LONG
	    static const int length = 32 + 2*sizeof(uint64_t);
#else /* ifndef TCL_WIDE_INT_IS_LONG */
	    static const int length = 32 + 2*sizeof(uint32_t);
#endif /* TCL_WIDE_INT_IS_LONG */

	    void *sPtr, *tPtr;
	    unsigned num;

	    if (strlen(name) == length && sscanf(name, "##ID##%p##%p##%u##", &sPtr, &tPtr, &num) == 3) {
		assert(hPtr);







|

|







1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
	hPtr = Tcl_CreateHashEntry(&sharedTextPtr->markTable, name, &dummy);
	markPtr = Tcl_GetHashValue(hPtr);
    }

    if (!markPtr) {
	if (name[0] == '#' && name[1] == '#' && name[2] == 'I') {
#ifdef TCL_WIDE_INT_IS_LONG
	    static const size_t length = 32 + 2*sizeof(uint64_t);
#else /* ifndef TCL_WIDE_INT_IS_LONG */
	    static const size_t length = 32 + 2*sizeof(uint32_t);
#endif /* TCL_WIDE_INT_IS_LONG */

	    void *sPtr, *tPtr;
	    unsigned num;

	    if (strlen(name) == length && sscanf(name, "##ID##%p##%p##%u##", &sPtr, &tPtr, &num) == 3) {
		assert(hPtr);

Changes to generic/tkTextPriv.h.

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
};

#endif /* _TKTEXTPRIV */

#ifdef _TK_NEED_IMPLEMENTATION

#include <assert.h>

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif

/*
 *----------------------------------------------------------------------
 *
 * TkTextIsSpecialMark --
 *
 *	Test whether this is a special mark: "insert", or "current".







<
<
<
<
<
<







43
44
45
46
47
48
49






50
51
52
53
54
55
56
};

#endif /* _TKTEXTPRIV */

#ifdef _TK_NEED_IMPLEMENTATION

#include <assert.h>







/*
 *----------------------------------------------------------------------
 *
 * TkTextIsSpecialMark --
 *
 *	Test whether this is a special mark: "insert", or "current".

Changes to generic/tkTextTag.c.

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <assert.h>
#include <stdlib.h>

#ifndef MAX
# define MAX(a,b) (((int) a) < ((int) b) ? b : a)
#endif

#if NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Support of tk8.5.







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <assert.h>
#include <stdlib.h>

#ifndef MAX
# define MAX(a,b) (((int) a) < ((int) b) ? b : a)
#endif

#ifdef NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Support of tk8.5.
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
    assert(sharedTextPtr);

    if (!tagPtr) {
	return;
    }

    assert(tagPtr->undoTagListIndex >= 0);
    assert(tagPtr->undoTagListIndex < sharedTextPtr->undoTagListCount);

    if (tagPtr->recentTagAddRemoveToken) {
	free(tagPtr->recentTagAddRemoveToken);
	DEBUG_ALLOC(tkTextCountDestroyUndoToken++);
	tagPtr->recentTagAddRemoveToken = NULL;
    }
    if (tagPtr->recentChangePriorityToken) {







|







2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
    assert(sharedTextPtr);

    if (!tagPtr) {
	return;
    }

    assert(tagPtr->undoTagListIndex >= 0);
    assert(tagPtr->undoTagListIndex < (int) sharedTextPtr->undoTagListCount);

    if (tagPtr->recentTagAddRemoveToken) {
	free(tagPtr->recentTagAddRemoveToken);
	DEBUG_ALLOC(tkTextCountDestroyUndoToken++);
	tagPtr->recentTagAddRemoveToken = NULL;
    }
    if (tagPtr->recentChangePriorityToken) {
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
    assert(sharedTextPtr->undoStack);

    if (!tagPtr) {
	return;
    }

    assert(tagPtr->undoTagListIndex >= 0);
    assert(tagPtr->undoTagListIndex < sharedTextPtr->undoTagListCount);

    if (tagPtr->recentTagAddRemoveToken) {
	if (tagPtr->recentTagAddRemoveTokenIsNull) {
	    free(tagPtr->recentTagAddRemoveToken);
	    DEBUG_ALLOC(tkTextCountDestroyUndoToken++);
	} else {
	    TkTextUndoPushItem(sharedTextPtr->undoStack, tagPtr->recentTagAddRemoveToken, 0);







|







2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
    assert(sharedTextPtr->undoStack);

    if (!tagPtr) {
	return;
    }

    assert(tagPtr->undoTagListIndex >= 0);
    assert(tagPtr->undoTagListIndex < (int) sharedTextPtr->undoTagListCount);

    if (tagPtr->recentTagAddRemoveToken) {
	if (tagPtr->recentTagAddRemoveTokenIsNull) {
	    free(tagPtr->recentTagAddRemoveToken);
	    DEBUG_ALLOC(tkTextCountDestroyUndoToken++);
	} else {
	    TkTextUndoPushItem(sharedTextPtr->undoStack, tagPtr->recentTagAddRemoveToken, 0);
3150
3151
3152
3153
3154
3155
3156

3157
3158
3159
3160
3161
3162
3163

    const TkSharedText *sharedTextPtr = textPtr->sharedTextPtr;
    TkBitField *includeBits = NULL;
    TkBitField *discardBits = NULL;
    bool discardSelection = false;
    TkTextTag **arrayPtr;
    int index, countTags, i;


    for (i = 3; i < objc; ++i) {
	const char *option = Tcl_GetString(objv[i]);

	if (*option != '-') {
	    break;
	}







>







3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164

    const TkSharedText *sharedTextPtr = textPtr->sharedTextPtr;
    TkBitField *includeBits = NULL;
    TkBitField *discardBits = NULL;
    bool discardSelection = false;
    TkTextTag **arrayPtr;
    int index, countTags, i;
    unsigned k;

    for (i = 3; i < objc; ++i) {
	const char *option = Tcl_GetString(objv[i]);

	if (*option != '-') {
	    break;
	}
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
    if (discardBits) {
	TkBitRemove(includeBits, discardBits);
    }

    arrayPtr = malloc(sharedTextPtr->numEnabledTags * sizeof(TkTextTag *));
    countTags = 0;

    for (i = TkBitFindFirst(includeBits); i != TK_BIT_NPOS; i = TkBitFindNext(includeBits, i)) {
	arrayPtr[countTags++] = sharedTextPtr->tagLookup[i];
    }

    AppendTags(interp, countTags, arrayPtr);
    free(arrayPtr);

    TkBitDecrRefCount(includeBits);
    if (discardBits) {







|
|







3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
    if (discardBits) {
	TkBitRemove(includeBits, discardBits);
    }

    arrayPtr = malloc(sharedTextPtr->numEnabledTags * sizeof(TkTextTag *));
    countTags = 0;

    for (k = TkBitFindFirst(includeBits); k != TK_BIT_NPOS; k = TkBitFindNext(includeBits, k)) {
	arrayPtr[countTags++] = sharedTextPtr->tagLookup[k];
    }

    AppendTags(interp, countTags, arrayPtr);
    free(arrayPtr);

    TkBitDecrRefCount(includeBits);
    if (discardBits) {

Changes to generic/tkTextTagSet.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tkTextTagSet.c --
 *
 *	This module implements a set for tagging information.
 *
 * Copyright (c) 2015-2017 Gregor Cramer
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkTextTagSet.h"

#if !(__STDC_VERSION__ >= 199901L)
# define _TK_NEED_IMPLEMENTATION
# include "tkTextTagSetPriv.h"
#endif

#if !TK_TEXT_DONT_USE_BITFIELDS

# include <assert.h>













|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * tkTextTagSet.c --
 *
 *	This module implements a set for tagging information.
 *
 * Copyright (c) 2015-2017 Gregor Cramer
 *
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkTextTagSet.h"

#ifndef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkTextTagSetPriv.h"
#endif

#if !TK_TEXT_DONT_USE_BITFIELDS

# include <assert.h>
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
TkTextTagSetToBits(
    const TkTextTagSet *src,
    int size)
{
    assert(src);

    if (src->base.isSetFlag) {
	return TkBitFromSet(&src->set, size < 0 ? TkIntSetMax(&src->set) + 1 : size);
    }

    if (size < 0 || TkBitSize(&src->bf) == size) {
	((TkTextTagSet *) src)->base.refCount += 1;
	return (TkBitField *) &src->bf;
    }

    return TkBitCopy(&src->bf, size);
}








|


|







188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
TkTextTagSetToBits(
    const TkTextTagSet *src,
    int size)
{
    assert(src);

    if (src->base.isSetFlag) {
	return TkBitFromSet(&src->set, size < 0 ? (int) TkIntSetMax(&src->set) + 1 : size);
    }

    if (size < 0 || (int) TkBitSize(&src->bf) == size) {
	((TkTextTagSet *) src)->base.refCount += 1;
	return (TkBitField *) &src->bf;
    }

    return TkBitCopy(&src->bf, size);
}

995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
	    }
	}
    }

    return TK_TEXT_TAG_SET_NPOS;
}

# if !NDEBUG

void
TkTextTagSetPrint(
    const TkTextTagSet *set)
{
    if (!set) {
	printf("<null>\n");
    } else if (TkTextTagSetIsEmpty(set)) {
	printf("<empty>\n");
    } else if (set->base.isSetFlag) {
	TkIntSetPrint(&set->set);
    } else {
	TkBitPrint(&set->bf);
    }
}

# endif /* !NDEBUG */
# if 0

/*
 * These functions are not needed anymore, but shouldn't be removed, because sometimes
 * any of these functions might be useful.
 */








|
















|







995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
	    }
	}
    }

    return TK_TEXT_TAG_SET_NPOS;
}

#ifndef NDEBUG

void
TkTextTagSetPrint(
    const TkTextTagSet *set)
{
    if (!set) {
	printf("<null>\n");
    } else if (TkTextTagSetIsEmpty(set)) {
	printf("<empty>\n");
    } else if (set->base.isSetFlag) {
	TkIntSetPrint(&set->set);
    } else {
	TkBitPrint(&set->bf);
    }
}

# endif /* NDEBUG */
# if 0

/*
 * These functions are not needed anymore, but shouldn't be removed, because sometimes
 * any of these functions might be useful.
 */

1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
    }
    return TkIntSetJoinOfDifferences(MakeCopyIfNeeded(dst), ts1, ts2);
}

#endif  /* !TK_TEXT_USE_BITFIELDS */


#if __STDC_VERSION__ >= 199901L
/* Additionally we need stand-alone object code. */
#define inline extern
#if !TK_TEXT_DONT_USE_BITFIELDS
inline TkTextTagSet *TkTextTagSetNew(unsigned size);
inline unsigned TkTextTagSetRefCount(const TkTextTagSet *ts);
inline void TkTextTagSetIncrRefCount(TkTextTagSet *ts);
inline unsigned TkTextTagSetDecrRefCount(TkTextTagSet *ts);
inline TkTextTagSet *TkTextTagSetCopy(const TkTextTagSet *src);
inline bool TkTextTagSetIsEmpty(const TkTextTagSet *ts);
inline bool TkTextTagSetIsBitField(const TkTextTagSet *ts);
inline unsigned TkTextTagSetSize(const TkTextTagSet *ts);
inline unsigned TkTextTagSetCount(const TkTextTagSet *ts);
inline bool TkTextTagSetTest(const TkTextTagSet *ts, unsigned n);
inline bool TkTextTagSetNone(const TkTextTagSet *ts);
inline bool TkTextTagSetAny(const TkTextTagSet *ts);
inline bool TkTextTagSetIsEqual(const TkTextTagSet *ts1, const TkTextTagSet *ts2);
inline bool TkTextTagSetContains(const TkTextTagSet *ts1, const TkTextTagSet *ts2);
inline bool TkTextTagSetDisjunctive(const TkTextTagSet *ts1, const TkTextTagSet *ts2);
inline bool TkTextTagSetIntersects(const TkTextTagSet *ts1, const TkTextTagSet *ts2);
inline bool TkTextTagSetIntersectionIsEqual(const TkTextTagSet *ts1, const TkTextTagSet *ts2,
    const TkBitField *bf);
inline bool TkTextTagBitContainsSet(const TkBitField *bf, const TkTextTagSet *ts);
inline bool TkTextTagSetIsEqualBits(const TkTextTagSet *ts, const TkBitField *bf);
inline bool TkTextTagSetContainsBits(const TkTextTagSet *ts, const TkBitField *bf);
inline bool TkTextTagSetDisjunctiveBits(const TkTextTagSet *ts, const TkBitField *bf);
inline bool TkTextTagSetIntersectsBits(const TkTextTagSet *ts, const TkBitField *bf);
inline unsigned TkTextTagSetFindFirst(const TkTextTagSet *ts);
inline unsigned TkTextTagSetFindNext(const TkTextTagSet *ts, unsigned prev);
inline TkTextTagSet *TkTextTagSetAddOrErase(TkTextTagSet *ts, unsigned n, bool value);
inline unsigned TkTextTagSetRangeSize(const TkTextTagSet *ts);
inline const unsigned char *TkTextTagSetData(const TkTextTagSet *ts);
inline unsigned TkTextTagSetByteSize(const TkTextTagSet *ts);
#else /* integer set only implementation **************************************/
inline TkIntSet *TkTextTagSetNew(unsigned size);
inline TkIntSet *TkTextTagSetResize(TkIntSet *ts, unsigned newSize);
inline void TkTextTagSetDestroy(TkIntSet **tsPtr);
inline unsigned TkTextTagSetRefCount(const TkIntSet *ts);
inline void TkTextTagSetIncrRefCount(TkIntSet *ts);
inline unsigned TkTextTagSetDecrRefCount(TkIntSet *ts);
inline TkIntSet *TkTextTagSetCopy(const TkIntSet *src);
inline bool TkTextTagSetIsEmpty(const TkIntSet *ts);
inline bool TkTextTagSetIsBitField(const TkIntSet *ts);
inline unsigned TkTextTagSetSize(const TkIntSet *ts);
inline unsigned TkTextTagSetCount(const TkIntSet *ts);
inline bool TkTextTagSetTest(const TkIntSet *ts, unsigned n);
inline bool TkTextTagSetNone(const TkIntSet *ts);
inline bool TkTextTagSetAny(const TkIntSet *ts);
inline bool TkTextTagSetIsEqual(const TkIntSet *ts1, const TkIntSet *ts2);
inline bool TkTextTagSetContains(const TkIntSet *ts1, const TkIntSet *ts2);
inline bool TkTextTagSetDisjunctive(const TkIntSet *ts1, const TkIntSet *ts2);
inline bool TkTextTagSetIntersects(const TkIntSet *ts1, const TkIntSet *ts2);
inline bool TkTextTagSetIntersectionIsEqual(const TkIntSet *ts1, const TkIntSet *ts2,
    const TkBitField *bf);
inline bool TkTextTagBitContainsSet(const TkBitField *bf, const TkIntSet *ts);
inline bool TkTextTagSetIsEqualBits(const TkIntSet *ts, const TkBitField *bf);
inline bool TkTextTagSetContainsBits(const TkIntSet *ts, const TkBitField *bf);
inline bool TkTextTagSetDisjunctiveBits(const TkIntSet *ts, const TkBitField *bf);
inline bool TkTextTagSetIntersectsBits(const TkIntSet *ts, const TkBitField *bf);
inline unsigned TkTextTagSetFindFirst(const TkIntSet *ts);
inline unsigned TkTextTagSetFindNext(const TkIntSet *ts, unsigned prev);
inline unsigned TkTextTagSetFindFirstInIntersection(const TkIntSet *ts, const TkBitField *bf);
inline TkIntSet *TkTextTagSetAddOrErase(TkIntSet *ts, unsigned n, bool value);
inline TkIntSet *TkTextTagSetClear(TkIntSet *ts);
inline unsigned TkTextTagSetRangeSize(const TkIntSet *ts);
inline const unsigned char *TkTextTagSetData(const TkIntSet *ts);
inline unsigned TkTextTagSetByteSize(const TkIntSet *ts);
#endif /* !TK_TEXT_DONT_USE_BITFIELDS */
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */







|

<

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|
|
|
|
|




1661
1662
1663
1664
1665
1666
1667
1668
1669

1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
    }
    return TkIntSetJoinOfDifferences(MakeCopyIfNeeded(dst), ts1, ts2);
}

#endif  /* !TK_TEXT_USE_BITFIELDS */


#ifdef TK_C99_INLINE_SUPPORT
/* Additionally we need stand-alone object code. */

#if !TK_TEXT_DONT_USE_BITFIELDS
extern TkTextTagSet *TkTextTagSetNew(unsigned size);
extern unsigned TkTextTagSetRefCount(const TkTextTagSet *ts);
extern void TkTextTagSetIncrRefCount(TkTextTagSet *ts);
extern unsigned TkTextTagSetDecrRefCount(TkTextTagSet *ts);
extern TkTextTagSet *TkTextTagSetCopy(const TkTextTagSet *src);
extern bool TkTextTagSetIsEmpty(const TkTextTagSet *ts);
extern bool TkTextTagSetIsBitField(const TkTextTagSet *ts);
extern unsigned TkTextTagSetSize(const TkTextTagSet *ts);
extern unsigned TkTextTagSetCount(const TkTextTagSet *ts);
extern bool TkTextTagSetTest(const TkTextTagSet *ts, unsigned n);
extern bool TkTextTagSetNone(const TkTextTagSet *ts);
extern bool TkTextTagSetAny(const TkTextTagSet *ts);
extern bool TkTextTagSetIsEqual(const TkTextTagSet *ts1, const TkTextTagSet *ts2);
extern bool TkTextTagSetContains(const TkTextTagSet *ts1, const TkTextTagSet *ts2);
extern bool TkTextTagSetDisjunctive(const TkTextTagSet *ts1, const TkTextTagSet *ts2);
extern bool TkTextTagSetIntersects(const TkTextTagSet *ts1, const TkTextTagSet *ts2);
extern bool TkTextTagSetIntersectionIsEqual(const TkTextTagSet *ts1, const TkTextTagSet *ts2,
    const TkBitField *bf);
extern bool TkTextTagBitContainsSet(const TkBitField *bf, const TkTextTagSet *ts);
extern bool TkTextTagSetIsEqualBits(const TkTextTagSet *ts, const TkBitField *bf);
extern bool TkTextTagSetContainsBits(const TkTextTagSet *ts, const TkBitField *bf);
extern bool TkTextTagSetDisjunctiveBits(const TkTextTagSet *ts, const TkBitField *bf);
extern bool TkTextTagSetIntersectsBits(const TkTextTagSet *ts, const TkBitField *bf);
extern unsigned TkTextTagSetFindFirst(const TkTextTagSet *ts);
extern unsigned TkTextTagSetFindNext(const TkTextTagSet *ts, unsigned prev);
extern TkTextTagSet *TkTextTagSetAddOrErase(TkTextTagSet *ts, unsigned n, bool value);
extern unsigned TkTextTagSetRangeSize(const TkTextTagSet *ts);
extern const unsigned char *TkTextTagSetData(const TkTextTagSet *ts);
extern unsigned TkTextTagSetByteSize(const TkTextTagSet *ts);
#else /* integer set only implementation **************************************/
extern TkIntSet *TkTextTagSetNew(unsigned size);
extern TkIntSet *TkTextTagSetResize(TkIntSet *ts, unsigned newSize);
extern void TkTextTagSetDestroy(TkIntSet **tsPtr);
extern unsigned TkTextTagSetRefCount(const TkIntSet *ts);
extern void TkTextTagSetIncrRefCount(TkIntSet *ts);
extern unsigned TkTextTagSetDecrRefCount(TkIntSet *ts);
extern TkIntSet *TkTextTagSetCopy(const TkIntSet *src);
extern bool TkTextTagSetIsEmpty(const TkIntSet *ts);
extern bool TkTextTagSetIsBitField(const TkIntSet *ts);
extern unsigned TkTextTagSetSize(const TkIntSet *ts);
extern unsigned TkTextTagSetCount(const TkIntSet *ts);
extern bool TkTextTagSetTest(const TkIntSet *ts, unsigned n);
extern bool TkTextTagSetNone(const TkIntSet *ts);
extern bool TkTextTagSetAny(const TkIntSet *ts);
extern bool TkTextTagSetIsEqual(const TkIntSet *ts1, const TkIntSet *ts2);
extern bool TkTextTagSetContains(const TkIntSet *ts1, const TkIntSet *ts2);
extern bool TkTextTagSetDisjunctive(const TkIntSet *ts1, const TkIntSet *ts2);
extern bool TkTextTagSetIntersects(const TkIntSet *ts1, const TkIntSet *ts2);
extern bool TkTextTagSetIntersectionIsEqual(const TkIntSet *ts1, const TkIntSet *ts2,
    const TkBitField *bf);
extern bool TkTextTagBitContainsSet(const TkBitField *bf, const TkIntSet *ts);
extern bool TkTextTagSetIsEqualBits(const TkIntSet *ts, const TkBitField *bf);
extern bool TkTextTagSetContainsBits(const TkIntSet *ts, const TkBitField *bf);
extern bool TkTextTagSetDisjunctiveBits(const TkIntSet *ts, const TkBitField *bf);
extern bool TkTextTagSetIntersectsBits(const TkIntSet *ts, const TkBitField *bf);
extern unsigned TkTextTagSetFindFirst(const TkIntSet *ts);
extern unsigned TkTextTagSetFindNext(const TkIntSet *ts, unsigned prev);
extern unsigned TkTextTagSetFindFirstInIntersection(const TkIntSet *ts, const TkBitField *bf);
extern TkIntSet *TkTextTagSetAddOrErase(TkIntSet *ts, unsigned n, bool value);
extern TkIntSet *TkTextTagSetClear(TkIntSet *ts);
extern unsigned TkTextTagSetRangeSize(const TkIntSet *ts);
extern const unsigned char *TkTextTagSetData(const TkIntSet *ts);
extern unsigned TkTextTagSetByteSize(const TkIntSet *ts);
#endif /* !TK_TEXT_DONT_USE_BITFIELDS */
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */

Changes to generic/tkTextTagSet.h.

12
13
14
15
16
17
18

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 */

#ifndef _TKTEXTTAGSET
#define _TKTEXTTAGSET

#include "tkBitField.h"
#include "tkIntSet.h"


#include <stdint.h>

#if defined(__GNUC__) || defined(__clang__)
# define __warn_unused__ __attribute__((warn_unused_result))
#else
# define __warn_unused__
#endif

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


/*
 * Currently our implementation is using a shared bitfield/integer set implementation.
 * Bitfields will be used as long as the number of tags is below a certain limit
 * (will be satisfied in most applications), but in some sophisticated applications
 * this limit will be exceeded, and in this case the integer set comes into play,
 * because a bitfield is too memory hungry with a large number of tags. Bitfields







>









<
<
<
<
<
<







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28






29
30
31
32
33
34
35
 */

#ifndef _TKTEXTTAGSET
#define _TKTEXTTAGSET

#include "tkBitField.h"
#include "tkIntSet.h"
#include "tkBool.h"

#include <stdint.h>

#if defined(__GNUC__) || defined(__clang__)
# define __warn_unused__ __attribute__((warn_unused_result))
#else
# define __warn_unused__
#endif








/*
 * Currently our implementation is using a shared bitfield/integer set implementation.
 * Bitfields will be used as long as the number of tags is below a certain limit
 * (will be satisfied in most applications), but in some sophisticated applications
 * this limit will be exceeded, and in this case the integer set comes into play,
 * because a bitfield is too memory hungry with a large number of tags. Bitfields
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
TkTextTagSet *TkTextTagSetClear(TkTextTagSet *ts) __warn_unused__;

inline unsigned TkTextTagSetRangeSize(const TkTextTagSet *ts);

inline const unsigned char *TkTextTagSetData(const TkTextTagSet *ts);
inline unsigned TkTextTagSetByteSize(const TkTextTagSet *ts);

# if !NDEBUG
void TkTextTagSetPrint(const TkTextTagSet *set);
# endif


# if 0

/*







|







150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
TkTextTagSet *TkTextTagSetClear(TkTextTagSet *ts) __warn_unused__;

inline unsigned TkTextTagSetRangeSize(const TkTextTagSet *ts);

inline const unsigned char *TkTextTagSetData(const TkTextTagSet *ts);
inline unsigned TkTextTagSetByteSize(const TkTextTagSet *ts);

# ifndef NDEBUG
void TkTextTagSetPrint(const TkTextTagSet *set);
# endif


# if 0

/*
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
inline unsigned TkTextTagSetByteSize(const TkIntSet *ts);

#endif /* !TK_TEXT_DONT_USE_BITFIELDS */


#undef __warn_unused__

#if __STDC_VERSION__ >= 199901L
# define _TK_NEED_IMPLEMENTATION
# include "tkTextTagSetPriv.h"
# undef _TK_NEED_IMPLEMENTATION
#endif

#endif /* _TKTEXTTAGSET */
/* vi:set ts=8 sw=4: */







|


<

<


267
268
269
270
271
272
273
274
275
276

277

278
279
inline unsigned TkTextTagSetByteSize(const TkIntSet *ts);

#endif /* !TK_TEXT_DONT_USE_BITFIELDS */


#undef __warn_unused__

#ifdef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkTextTagSetPriv.h"

#endif

#endif /* _TKTEXTTAGSET */
/* vi:set ts=8 sw=4: */

Changes to generic/tkTextTagSetPriv.h.

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

#ifndef _TK
#include "tk.h"
#endif

#include <assert.h>

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


#if !TK_TEXT_DONT_USE_BITFIELDS /* shared implementation ****************************/

inline
TkTextTagSet *
TkTextTagSetNew(
    unsigned size)







<
<
<
<
<
<







62
63
64
65
66
67
68






69
70
71
72
73
74
75

#ifndef _TK
#include "tk.h"
#endif

#include <assert.h>








#if !TK_TEXT_DONT_USE_BITFIELDS /* shared implementation ****************************/

inline
TkTextTagSet *
TkTextTagSetNew(
    unsigned size)

Changes to generic/tkTextUndo.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 */

#include "tkTextUndo.h"
#include "tkInt.h"
#include "tkAlloc.h"
#include <assert.h>

#if !(__STDC_VERSION__ >= 199901L)
# define _TK_NEED_IMPLEMENTATION
# include "tkTextUndoPriv.h"
#endif

#ifndef MAX
# define MAX(a,b) ((a) < (b) ? b : a)
#endif







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 */

#include "tkTextUndo.h"
#include "tkInt.h"
#include "tkAlloc.h"
#include <assert.h>

#ifndef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkTextUndoPriv.h"
#endif

#ifndef MAX
# define MAX(a,b) ((a) < (b) ? b : a)
#endif
145
146
147
148
149
150
151
152


153
154
155
156
157
158
159

    if (current) {
	FreeItems(stack, &current->data);
    }

    if (force || !current || current->capacity > InitialCapacity) {
	static unsigned Size = ATOM_SIZE(InitialCapacity);
	current = stack->current = memset(realloc(current, Size), 0, Size);


	current->capacity = InitialCapacity;
    }

    current->data.arraySize = 0;
    current->data.size = 0;
    current->undoSize = 0;
}







|
>
>







145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

    if (current) {
	FreeItems(stack, &current->data);
    }

    if (force || !current || current->capacity > InitialCapacity) {
	static unsigned Size = ATOM_SIZE(InitialCapacity);
	current = stack->current = realloc(current, Size);
	/* NOTE: MSVS 2010 throws internal compiler error when using memset(realloc()). */
	memset(current, 0, Size);
	current->capacity = InitialCapacity;
    }

    current->data.arraySize = 0;
    current->data.size = 0;
    current->undoSize = 0;
}
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
	stack->undoDepth += 1;
	stack->undoSize += atom->data.size;
	stack->undoItems += atom->data.arraySize;
    } else if (stack->doingUndo) {
	/*
	 * We'll push a redo atom while performing an undo.
	 */
	assert(stack->maxRedoDepth <= 0 || stack->redoDepth < stack->maxRedoDepth);
	atom = stack->last ? stack->last->next : stack->root;
	SwapCurrent(stack, atom);
	stack->redoDepth += 1;
	stack->redoSize += atom->data.size;
	stack->redoItems += atom->data.arraySize;
    } else if (stack->last && stack->undoDepth == stack->maxUndoDepth) {
	/*







|







300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
	stack->undoDepth += 1;
	stack->undoSize += atom->data.size;
	stack->undoItems += atom->data.arraySize;
    } else if (stack->doingUndo) {
	/*
	 * We'll push a redo atom while performing an undo.
	 */
	assert(stack->maxRedoDepth <= 0 || (int) stack->redoDepth < stack->maxRedoDepth);
	atom = stack->last ? stack->last->next : stack->root;
	SwapCurrent(stack, atom);
	stack->redoDepth += 1;
	stack->redoSize += atom->data.size;
	stack->redoItems += atom->data.arraySize;
    } else if (stack->last && stack->undoDepth == stack->maxUndoDepth) {
	/*
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552

	if ((0 < maxUndoDepth && maxUndoDepth < depth)
		|| (0 <= maxRedoDepth && (unsigned) maxRedoDepth < (unsigned) stack->maxRedoDepth)) {
	    unsigned deleteRedos = MIN(stack->redoDepth, depth - maxUndoDepth);

	    if (0 <= maxRedoDepth && maxRedoDepth < stack->maxRedoDepth) {
		deleteRedos = MIN(stack->redoDepth,
			MAX(deleteRedos, stack->maxRedoDepth - maxRedoDepth));
	    }

	    stack->redoDepth -= deleteRedos;
	    depth = maxUndoDepth - deleteRedos;

	    if (deleteRedos > 0) {
		MyUndoAtom *atom = stack->root;







|







540
541
542
543
544
545
546
547
548
549
550
551
552
553
554

	if ((0 < maxUndoDepth && maxUndoDepth < depth)
		|| (0 <= maxRedoDepth && (unsigned) maxRedoDepth < (unsigned) stack->maxRedoDepth)) {
	    unsigned deleteRedos = MIN(stack->redoDepth, depth - maxUndoDepth);

	    if (0 <= maxRedoDepth && maxRedoDepth < stack->maxRedoDepth) {
		deleteRedos = MIN(stack->redoDepth,
			MAX(deleteRedos, (unsigned) stack->maxRedoDepth - maxRedoDepth));
	    }

	    stack->redoDepth -= deleteRedos;
	    depth = maxUndoDepth - deleteRedos;

	    if (deleteRedos > 0) {
		MyUndoAtom *atom = stack->root;
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
TkTextUndoStackIsFull(
    const TkTextUndoStack stack)
{
    if (!stack) {
	return true;
    }
    if (stack->doingUndo) {
	return stack->maxRedoDepth >= 0 && stack->redoDepth >= stack->maxRedoDepth;
    }
    return stack->maxUndoDepth > 0 && stack->undoDepth >= stack->maxUndoDepth;
}


const TkTextUndoAtom *
TkTextUndoFirstUndoAtom(







|







946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
TkTextUndoStackIsFull(
    const TkTextUndoStack stack)
{
    if (!stack) {
	return true;
    }
    if (stack->doingUndo) {
	return stack->maxRedoDepth >= 0 && (int) stack->redoDepth >= stack->maxRedoDepth;
    }
    return stack->maxUndoDepth > 0 && stack->undoDepth >= stack->maxUndoDepth;
}


const TkTextUndoAtom *
TkTextUndoFirstUndoAtom(
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
	}
    }

    return NULL;
}


#if __STDC_VERSION__ >= 199901L
/* Additionally we need stand-alone object code. */
#define inline extern
inline void TkTextUndoSetContext(TkTextUndoStack stack, TkTextUndoContext context);
inline TkTextUndoContext TkTextUndoGetContext(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetMaxUndoDepth(const TkTextUndoStack stack);
inline int TkTextUndoGetMaxRedoDepth(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetMaxSize(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentDepth(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentSize(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentUndoStackDepth(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentRedoStackDepth(const TkTextUndoStack stack);
inline unsigned TkTextUndoCountUndoItems(const TkTextUndoStack stack);
inline unsigned TkTextUndoCountRedoItems(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentUndoSize(const TkTextUndoStack stack);
inline unsigned TkTextUndoGetCurrentRedoSize(const TkTextUndoStack stack);
inline unsigned TkTextUndoCountCurrentUndoItems(const TkTextUndoStack stack);
inline unsigned TkTextUndoCountCurrentRedoItems(const TkTextUndoStack stack);
inline bool TkTextUndoContentIsIrreversible(const TkTextUndoStack stack);
inline bool TkTextUndoContentIsModified(const TkTextUndoStack stack);
inline bool TkTextUndoIsPerformingUndo(const TkTextUndoStack stack);
inline bool TkTextUndoIsPerformingRedo(const TkTextUndoStack stack);
inline bool TkTextUndoIsPerformingUndoRedo(const TkTextUndoStack stack);
inline const TkTextUndoAtom *TkTextUndoCurrentUndoAtom(const TkTextUndoStack stack);
inline const TkTextUndoAtom *TkTextUndoCurrentRedoAtom(const TkTextUndoStack stack);
inline const TkTextUndoSubAtom *TkTextUndoGetLastUndoSubAtom(const TkTextUndoStack stack);
inline bool TkTextUndoUndoStackIsFull(const TkTextUndoStack stack);
inline bool TkTextUndoRedoStackIsFull(const TkTextUndoStack stack);
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */







|

<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|



1038
1039
1040
1041
1042
1043
1044
1045
1046

1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
	}
    }

    return NULL;
}


#ifdef TK_C99_INLINE_SUPPORT
/* Additionally we need stand-alone object code. */

extern void TkTextUndoSetContext(TkTextUndoStack stack, TkTextUndoContext context);
extern TkTextUndoContext TkTextUndoGetContext(const TkTextUndoStack stack);
extern unsigned TkTextUndoGetMaxUndoDepth(const TkTextUndoStack stack);
extern int TkTextUndoGetMaxRedoDepth(const TkTextUndoStack stack);
extern unsigned TkTextUndoGetMaxSize(const TkTextUndoStack stack);
extern unsigned TkTextUndoGetCurrentDepth(const TkTextUndoStack stack);
extern unsigned TkTextUndoGetCurrentSize(const TkTextUndoStack stack);
extern unsigned TkTextUndoGetCurrentUndoStackDepth(const TkTextUndoStack stack);
extern unsigned TkTextUndoGetCurrentRedoStackDepth(const TkTextUndoStack stack);
extern unsigned TkTextUndoCountUndoItems(const TkTextUndoStack stack);
extern unsigned TkTextUndoCountRedoItems(const TkTextUndoStack stack);
extern unsigned TkTextUndoGetCurrentUndoSize(const TkTextUndoStack stack);
extern unsigned TkTextUndoGetCurrentRedoSize(const TkTextUndoStack stack);
extern unsigned TkTextUndoCountCurrentUndoItems(const TkTextUndoStack stack);
extern unsigned TkTextUndoCountCurrentRedoItems(const TkTextUndoStack stack);
extern bool TkTextUndoContentIsIrreversible(const TkTextUndoStack stack);
extern bool TkTextUndoContentIsModified(const TkTextUndoStack stack);
extern bool TkTextUndoIsPerformingUndo(const TkTextUndoStack stack);
extern bool TkTextUndoIsPerformingRedo(const TkTextUndoStack stack);
extern bool TkTextUndoIsPerformingUndoRedo(const TkTextUndoStack stack);
extern const TkTextUndoAtom *TkTextUndoCurrentUndoAtom(const TkTextUndoStack stack);
extern const TkTextUndoAtom *TkTextUndoCurrentRedoAtom(const TkTextUndoStack stack);
extern const TkTextUndoSubAtom *TkTextUndoGetLastUndoSubAtom(const TkTextUndoStack stack);
extern bool TkTextUndoUndoStackIsFull(const TkTextUndoStack stack);
extern bool TkTextUndoRedoStackIsFull(const TkTextUndoStack stack);
#endif /* __STDC_VERSION__ >= 199901L */

/* vi:set ts=8 sw=4: */

Changes to generic/tkTextUndo.h.

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

#ifndef _TKTEXTUNDO
#define _TKTEXTUNDO

#include "tkBool.h"
#include <stdint.h>

#ifndef _MSC_VER
# if __STDC_VERSION__ < 199901L
#  define inline /* we are not C99 conform */
# endif
#endif


/*
 * Our (private) stack type.
 */

struct TkTextUndoStack;
typedef struct TkTextUndoStack * TkTextUndoStack;







<
<
<
<
<
<







29
30
31
32
33
34
35






36
37
38
39
40
41
42

#ifndef _TKTEXTUNDO
#define _TKTEXTUNDO

#include "tkBool.h"
#include <stdint.h>








/*
 * Our (private) stack type.
 */

struct TkTextUndoStack;
typedef struct TkTextUndoStack * TkTextUndoStack;
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
 * pushed. Returns an error (TCL_ERROR) if no undo (redo) action is possible.
 */

int TkTextUndoDoUndo(TkTextUndoStack stack);
int TkTextUndoDoRedo(TkTextUndoStack stack);


#if __STDC_VERSION__ >= 199901L
# define _TK_NEED_IMPLEMENTATION
# include "tkTextUndoPriv.h"
# undef _TK_NEED_IMPLEMENTATION
#endif

#endif /* _TKTEXTUNDO */
/* vi:set ts=8 sw=4: */







|


<

<


234
235
236
237
238
239
240
241
242
243

244

245
246
 * pushed. Returns an error (TCL_ERROR) if no undo (redo) action is possible.
 */

int TkTextUndoDoUndo(TkTextUndoStack stack);
int TkTextUndoDoRedo(TkTextUndoStack stack);


#ifdef TK_C99_INLINE_SUPPORT
# define _TK_NEED_IMPLEMENTATION
# include "tkTextUndoPriv.h"

#endif

#endif /* _TKTEXTUNDO */
/* vi:set ts=8 sw=4: */

Changes to generic/tkTextUndoPriv.h.

101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

inline bool
TkTextUndoUndoStackIsFull(const TkTextUndoStack stack)
{ return !stack || (stack->maxUndoDepth > 0 && stack->undoDepth >= stack->maxUndoDepth); }

inline bool
TkTextUndoRedoStackIsFull(const TkTextUndoStack stack)
{ return !stack || (stack->maxRedoDepth >= 0 && stack->redoDepth >= stack->maxRedoDepth); }

inline unsigned
TkTextUndoCountCurrentUndoItems(const TkTextUndoStack stack)
{ assert(stack); return stack->current && !stack->doingUndo ? stack->current->data.arraySize : 0; }

inline unsigned
TkTextUndoCountCurrentRedoItems(const TkTextUndoStack stack)







|







101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

inline bool
TkTextUndoUndoStackIsFull(const TkTextUndoStack stack)
{ return !stack || (stack->maxUndoDepth > 0 && stack->undoDepth >= stack->maxUndoDepth); }

inline bool
TkTextUndoRedoStackIsFull(const TkTextUndoStack stack)
{ return !stack || (stack->maxRedoDepth >= 0 && (int) stack->redoDepth >= stack->maxRedoDepth); }

inline unsigned
TkTextUndoCountCurrentUndoItems(const TkTextUndoStack stack)
{ assert(stack); return stack->current && !stack->doingUndo ? stack->current->data.arraySize : 0; }

inline unsigned
TkTextUndoCountCurrentRedoItems(const TkTextUndoStack stack)

Changes to generic/tkTextWind.c.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include "tkPort.h"
#include "tkText.h"
#include "tkTextTagSet.h"
#include "tkTextUndo.h"
#include <assert.h>

#if NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Support of tk8.5.







|







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

#include "tkPort.h"
#include "tkText.h"
#include "tkTextTagSet.h"
#include "tkTextUndo.h"
#include <assert.h>

#ifdef NDEBUG
# define DEBUG(expr)
#else
# define DEBUG(expr) expr
#endif

/*
 * Support of tk8.5.

Changes to tests/text.test.

1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
12345
Line 4
bOy GIrl .#@? x_yz
!@#$%
Line 7"
    .t configure -state disabled
    .t delete 2.3
    .t g 2.0 2.end
} -cleanup {
    destroy .t
} -result {abcdefghijklm}
test text-8.6 {TextWidgetCmd procedure, "delete" option} -setup {
    text .t
} -body {
    .t insert 1.0 "Line 1







|







1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
12345
Line 4
bOy GIrl .#@? x_yz
!@#$%
Line 7"
    .t configure -state disabled
    .t delete 2.3
    .t get 2.0 2.end
} -cleanup {
    destroy .t
} -result {abcdefghijklm}
test text-8.6 {TextWidgetCmd procedure, "delete" option} -setup {
    text .t
} -body {
    .t insert 1.0 "Line 1

Changes to unix/Makefile.in.

944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
tkAtom.o: $(GENERIC_DIR)/tkAtom.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkAtom.c

tkBind.o: $(GENERIC_DIR)/tkBind.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkBind.c

tkBitField.o: $(GENERIC_DIR)/tkBitField.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkBitField.c

tkBitmap.o: $(GENERIC_DIR)/tkBitmap.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkBitmap.c

tkBusy.o: $(GENERIC_DIR)/tkBusy.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkBusy.c








|







944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
tkAtom.o: $(GENERIC_DIR)/tkAtom.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkAtom.c

tkBind.o: $(GENERIC_DIR)/tkBind.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkBind.c

tkBitField.o: $(GENERIC_DIR)/tkBitField.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkBitField.c

tkBitmap.o: $(GENERIC_DIR)/tkBitmap.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkBitmap.c

tkBusy.o: $(GENERIC_DIR)/tkBusy.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkBusy.c

1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
tkImgPhInstance.o: $(GENERIC_DIR)/tkImgPhInstance.c $(GENERIC_DIR)/tkImgPhoto.h
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPhInstance.c

tkOldTest.o: $(GENERIC_DIR)/tkOldTest.c
	$(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tkOldTest.c

tkQTree.o: $(GENERIC_DIR)/tkQTree.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkQTree.c

tkRangeList.o: $(GENERIC_DIR)/tkRangeList.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkRangeList.c

tkIntSet.o: $(GENERIC_DIR)/tkIntSet.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkIntSet.c

tkTest.o: $(GENERIC_DIR)/tkTest.c
	$(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tkTest.c

tkText.o: $(GENERIC_DIR)/tkText.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkText.c

tkTextBTree.o: $(GENERIC_DIR)/tkTextBTree.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextBTree.c

tkTextDisp.o: $(GENERIC_DIR)/tkTextDisp.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextDisp.c

tkTextImage.o: $(GENERIC_DIR)/tkTextImage.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextImage.c

tkTextIndex.o: $(GENERIC_DIR)/tkTextIndex.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextIndex.c

tkTextLineBreak.o: $(GENERIC_DIR)/tkTextLineBreak.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextLineBreak.c

tkTextMark.o: $(GENERIC_DIR)/tkTextMark.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextMark.c

tkTextTag.o: $(GENERIC_DIR)/tkTextTag.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextTag.c

tkTextTagSet.o: $(GENERIC_DIR)/tkTextTagSet.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextTagSet.c

tkTextUndo.o: $(GENERIC_DIR)/tkTextUndo.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextUndo.c

tkTextWind.o: $(GENERIC_DIR)/tkTextWind.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextWind.c

tkStubInit.o: $(GENERIC_DIR)/tkStubInit.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkStubInit.c

# Stub library binaries, these must be compiled for use in a shared library
# even though they will be placed in a static archive








|


|


|





|


|


|


|


|


|


|


|


|


|


|







1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
tkImgPhInstance.o: $(GENERIC_DIR)/tkImgPhInstance.c $(GENERIC_DIR)/tkImgPhoto.h
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkImgPhInstance.c

tkOldTest.o: $(GENERIC_DIR)/tkOldTest.c
	$(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tkOldTest.c

tkQTree.o: $(GENERIC_DIR)/tkQTree.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkQTree.c

tkRangeList.o: $(GENERIC_DIR)/tkRangeList.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkRangeList.c

tkIntSet.o: $(GENERIC_DIR)/tkIntSet.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkIntSet.c

tkTest.o: $(GENERIC_DIR)/tkTest.c
	$(CC) -c $(APP_CC_SWITCHES) $(GENERIC_DIR)/tkTest.c

tkText.o: $(GENERIC_DIR)/tkText.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkText.c

tkTextBTree.o: $(GENERIC_DIR)/tkTextBTree.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextBTree.c

tkTextDisp.o: $(GENERIC_DIR)/tkTextDisp.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextDisp.c

tkTextImage.o: $(GENERIC_DIR)/tkTextImage.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextImage.c

tkTextIndex.o: $(GENERIC_DIR)/tkTextIndex.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextIndex.c

tkTextLineBreak.o: $(GENERIC_DIR)/tkTextLineBreak.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextLineBreak.c

tkTextMark.o: $(GENERIC_DIR)/tkTextMark.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextMark.c

tkTextTag.o: $(GENERIC_DIR)/tkTextTag.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextTag.c

tkTextTagSet.o: $(GENERIC_DIR)/tkTextTagSet.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextTagSet.c

tkTextUndo.o: $(GENERIC_DIR)/tkTextUndo.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextUndo.c

tkTextWind.o: $(GENERIC_DIR)/tkTextWind.c
	$(CC) -std=c99 -c $(CC_SWITCHES) $(GENERIC_DIR)/tkTextWind.c

tkStubInit.o: $(GENERIC_DIR)/tkStubInit.c
	$(CC) -c $(CC_SWITCHES) $(GENERIC_DIR)/tkStubInit.c

# Stub library binaries, these must be compiled for use in a shared library
# even though they will be placed in a static archive