Tk Source Code

Changes On Branch bug-1096580fff
Login

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

Changes In Branch bug-1096580fff Excluding Merge-Ins

This is equivalent to a diff from 97e420e7 to 6c675535

2017-02-07
07:14
Explain why replacing soft hyphens by hard hyphens is done only on OS X Leaf check-in: 6c675535 user: fvogel tags: bug-1096580fff, soft-hyphen
2017-02-05
21:49
Make soft hyphens render (be displayed) when located at the end of a display line, even if the font used has no corresponding glyph check-in: 64d631fe user: fvogel tags: bug-1096580fff, soft-hyphen
19:29
Fix [7d967c68]: Tk application fault when ibud-daemon IME is restarted check-in: c9224070 user: jan.nijtmans tags: core-8-6-branch
17:41
Merge core-8-6-branch check-in: 1bf8023f user: fvogel tags: bug-1096580fff, soft-hyphen
17:17
Fix [ae32eb7e10]: Win + specific text widget configuration : textDisp-18.6, -20.2 -20.3 -20.4 fail check-in: f7e1ba37 user: fvogel tags: trunk
17:17
Fix [ae32eb7e10]: Win + specific text widget configuration : textDisp-18.6, -20.2 -20.3 -20.4 fail check-in: 97e420e7 user: fvogel tags: core-8-6-branch
2017-02-01
21:09
Remove old pack syntax from the scripts of the Tk test suite check-in: 75c8d750 user: fvogel tags: core-8-6-branch
2017-01-29
16:48
Remove superfluous 'textfonts' constraint in textDisp-20.1,2,3,4,5 Closed-Leaf check-in: 278779a8 user: fvogel tags: bug-ae32eb7e10

Changes to generic/tkTextDisp.c.

1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
	    if (elidesize > 0) {
		curIndex.byteIndex += elidesize;
		lastChunkPtr->numBytes += elidesize;
		breakByteOffset = lastChunkPtr->breakIndex
			= lastChunkPtr->numBytes;

		/*
		 * If have we have a tag toggle, there is a chance that
		 * invisibility state changed, so bail out.
		 */
	    } else if ((segPtr->typePtr == &tkTextToggleOffType)
		    || (segPtr->typePtr == &tkTextToggleOnType)) {
		if (segPtr->body.toggle.tagPtr->elideString != NULL) {
		    elide = (segPtr->typePtr == &tkTextToggleOffType)
			    ^ segPtr->body.toggle.tagPtr->elide;







|







1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
	    if (elidesize > 0) {
		curIndex.byteIndex += elidesize;
		lastChunkPtr->numBytes += elidesize;
		breakByteOffset = lastChunkPtr->breakIndex
			= lastChunkPtr->numBytes;

		/*
		 * If we have a tag toggle, there is a chance that
		 * invisibility state changed, so bail out.
		 */
	    } else if ((segPtr->typePtr == &tkTextToggleOffType)
		    || (segPtr->typePtr == &tkTextToggleOnType)) {
		if (segPtr->body.toggle.tagPtr->elideString != NULL) {
		    elide = (segPtr->typePtr == &tkTextToggleOffType)
			    ^ segPtr->body.toggle.tagPtr->elide;
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484








1485
1486
1487
1488
1489

1490
1491
1492

1493
1494
1495
1496
1497
1498
1499
	    }
	}

	gotTab = 0;
	maxBytes = segPtr->size - byteOffset;
	if (segPtr->typePtr == &tkTextCharType) {

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









	    if (!elide && justify == TK_JUSTIFY_LEFT) {
		char *p;

		for (p = segPtr->body.chars + byteOffset; *p != 0; p++) {
		    if (*p == '\t') {

			maxBytes = (p + 1 - segPtr->body.chars) - byteOffset;
			gotTab = 1;
			break;

		    }
		}
	    }

#if TK_LAYOUT_WITH_BASE_CHUNKS
	    if (baseCharChunkPtr != NULL) {
		int expectedX =







|
|
|
|

>
>
>
>
>
>
>
>





>
|
|
|
>







1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
	    }
	}

	gotTab = 0;
	maxBytes = segPtr->size - byteOffset;
	if (segPtr->typePtr == &tkTextCharType) {

            /*
             * See if there is a tab or soft hyphen in the current segment; if so,
             * only layout characters up to (and including) this character.
             */

            if (!elide) {
                const char *p;
                
                p = Tcl_UtfFindFirst(segPtr->body.chars + byteOffset, 0x00AD);
                if (p != NULL) {
                    maxBytes = (p + 2 - segPtr->body.chars) - byteOffset;
                }
            }
	    if (!elide && justify == TK_JUSTIFY_LEFT) {
		char *p;

		for (p = segPtr->body.chars + byteOffset; *p != 0; p++) {
		    if (*p == '\t') {
                        if ((p + 1 - segPtr->body.chars) - byteOffset <= maxBytes) {
                            maxBytes = (p + 1 - segPtr->body.chars) - byteOffset;
			    gotTab = 1;
			    break;
                        }
		    }
		}
	    }

#if TK_LAYOUT_WITH_BASE_CHUNKS
	    if (baseCharChunkPtr != NULL) {
		int expectedX =
7516
7517
7518
7519
7520
7521
7522
7523
7524
7525
7526
7527

7528
7529
7530
7531
7532
7533
7534
				 * TEXT_WRAPMODE_WORD. */
    register TkTextDispChunk *chunkPtr)
				/* Structure to fill in with information about
				 * this chunk. The x field has already been
				 * set by the caller. */
{
    Tk_Font tkfont;
    int nextX, bytesThatFit, count;
    CharInfo *ciPtr;
    char *p;
    TkTextSegment *nextPtr;
    Tk_FontMetrics fm;

#if TK_LAYOUT_WITH_BASE_CHUNKS
    const char *line;
    int lineOffset;
    BaseCharInfo *bciPtr;
    Tcl_DString *baseString;
#endif








|

|


>







7526
7527
7528
7529
7530
7531
7532
7533
7534
7535
7536
7537
7538
7539
7540
7541
7542
7543
7544
7545
				 * TEXT_WRAPMODE_WORD. */
    register TkTextDispChunk *chunkPtr)
				/* Structure to fill in with information about
				 * this chunk. The x field has already been
				 * set by the caller. */
{
    Tk_Font tkfont;
    int nextX, bytesThatFit;
    CharInfo *ciPtr;
    char *p, *p2;
    TkTextSegment *nextPtr;
    Tk_FontMetrics fm;
    int ch, nBytes;
#if TK_LAYOUT_WITH_BASE_CHUNKS
    const char *line;
    int lineOffset;
    BaseCharInfo *bciPtr;
    Tcl_DString *baseString;
#endif

7592
7593
7594
7595
7596
7597
7598
7599
7600
7601
7602
7603
7604
7605
7606
7607
		    lineOffset+chLen, lineOffset, -1, chunkPtr->x, -1, 0,
		    &nextX);
#else /* !TK_LAYOUT_WITH_BASE_CHUNKS */
	    bytesThatFit = CharChunkMeasureChars(chunkPtr, p, chLen, 0, -1,
		    chunkPtr->x, -1, 0, &nextX);
#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
	}
	if ((nextX < maxX) && ((p[bytesThatFit] == ' ')
		|| (p[bytesThatFit] == '\t'))) {
	    /*
	     * Space characters are funny, in that they are considered to fit
	     * if there is at least one pixel of space left on the line. Just
	     * give the space character whatever space is left.
	     */

	    nextX = maxX;







<
|







7603
7604
7605
7606
7607
7608
7609

7610
7611
7612
7613
7614
7615
7616
7617
		    lineOffset+chLen, lineOffset, -1, chunkPtr->x, -1, 0,
		    &nextX);
#else /* !TK_LAYOUT_WITH_BASE_CHUNKS */
	    bytesThatFit = CharChunkMeasureChars(chunkPtr, p, chLen, 0, -1,
		    chunkPtr->x, -1, 0, &nextX);
#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
	}

	if ((nextX < maxX) && (p[bytesThatFit] == ' ')) {
	    /*
	     * Space characters are funny, in that they are considered to fit
	     * if there is at least one pixel of space left on the line. Just
	     * give the space character whatever space is left.
	     */

	    nextX = maxX;
7680
7681
7682
7683
7684
7685
7686
7687
7688

7689
7690
7691
7692





7693
7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712



7713
7714

7715

7716
7717
7718
7719

7720
7721
7722
7723
7724
7725
7726
7727
     * Final update for the current base chunk data.
     */

    Tcl_DStringSetLength(baseString,lineOffset+ciPtr->numBytes);
    bciPtr->width = nextX - baseCharChunkPtr->x;

    /*
     * Finalize the base chunk if this chunk ends in a tab, which definitly
     * breaks the context and needs to be handled on a higher level.

     */

    if (ciPtr->numBytes > 0 && p[ciPtr->numBytes - 1] == '\t') {
	FinalizeBaseChunk(chunkPtr);





    }
#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */

    /*
     * Compute a break location. If we're in word wrap mode, a break can occur
     * after any space character, or at the end of the chunk if the next
     * segment (ignoring those with zero size) is not a character segment.
     */

    if (wrapMode != TEXT_WRAPMODE_WORD) {
	chunkPtr->breakIndex = chunkPtr->numBytes;
    } else {
	for (count = bytesThatFit, p += bytesThatFit - 1; count > 0;
		count--, p--) {
	    /*
	     * Don't use isspace(); effects are unpredictable and can lead to
	     * odd word-wrapping problems on some platforms. Also don't use
	     * Tcl_UniCharIsSpace here either, as it identifies non-breaking
	     * spaces as places to break. What we actually want is only the
	     * ASCII space characters, so use them explicitly...



	     */


	    switch (*p) {

	    case '\t': case '\n': case '\v': case '\f': case '\r': case ' ':
		chunkPtr->breakIndex = count;
		goto checkForNextChunk;
	    }

	}
    checkForNextChunk:
	if ((bytesThatFit + byteOffset) == segPtr->size) {
	    for (nextPtr = segPtr->nextPtr; nextPtr != NULL;
		    nextPtr = nextPtr->nextPtr) {
		if (nextPtr->size != 0) {
		    if (nextPtr->typePtr != &tkTextCharType) {
			chunkPtr->breakIndex = chunkPtr->numBytes;







|
|
>




>
>
>
>
>












|
|
|





>
>
>


>
|
>
|
|

|
>
|







7690
7691
7692
7693
7694
7695
7696
7697
7698
7699
7700
7701
7702
7703
7704
7705
7706
7707
7708
7709
7710
7711
7712
7713
7714
7715
7716
7717
7718
7719
7720
7721
7722
7723
7724
7725
7726
7727
7728
7729
7730
7731
7732
7733
7734
7735
7736
7737
7738
7739
7740
7741
7742
7743
7744
7745
7746
7747
7748
7749
     * Final update for the current base chunk data.
     */

    Tcl_DStringSetLength(baseString,lineOffset+ciPtr->numBytes);
    bciPtr->width = nextX - baseCharChunkPtr->x;

    /*
     * Finalize the base chunk if this chunk ends in a tab or soft hyphen,
     * which definitely breaks the context and needs to be handled on a
     * higher level.
     */

    if (ciPtr->numBytes > 0 && p[ciPtr->numBytes - 1] == '\t') {
	FinalizeBaseChunk(chunkPtr);
    } else {
        TkUtfToUniChar(Tcl_UtfPrev(p + ciPtr->numBytes, p), &ch);
        if (ch == 0x00AD) {
            FinalizeBaseChunk(chunkPtr);
        }
    }
#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */

    /*
     * Compute a break location. If we're in word wrap mode, a break can occur
     * after any space character, or at the end of the chunk if the next
     * segment (ignoring those with zero size) is not a character segment.
     */

    if (wrapMode != TEXT_WRAPMODE_WORD) {
	chunkPtr->breakIndex = chunkPtr->numBytes;
    } else {
        p2 = p + bytesThatFit;
        while (p2 - p > 0) {
            /*
	     * Don't use isspace(); effects are unpredictable and can lead to
	     * odd word-wrapping problems on some platforms. Also don't use
	     * Tcl_UniCharIsSpace here either, as it identifies non-breaking
	     * spaces as places to break. What we actually want is only the
	     * ASCII space characters, so use them explicitly...
             * 0x09 is '\t', 0x0A is '\n', 0x0B is '\v', 0x0C is '\f',
             * 0x0D is '\r', 0x20 is ' ', 0x2D is '-', and 0x00AD is the soft
             * hyphen
	     */

            nBytes = TkUtfToUniChar(Tcl_UtfPrev(p2, p), &ch);
            switch (ch) {
            case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D:
                    case 0x20: case 0x2D: case 0x00AD:
		chunkPtr->breakIndex = p2 - p;
		goto checkForNextChunk;
            }
            p2 -= nBytes;
        }
    checkForNextChunk:
	if ((bytesThatFit + byteOffset) == segPtr->size) {
	    for (nextPtr = segPtr->nextPtr; nextPtr != NULL;
		    nextPtr = nextPtr->nextPtr) {
		if (nextPtr->size != 0) {
		    if (nextPtr->typePtr != &tkTextCharType) {
			chunkPtr->breakIndex = chunkPtr->numBytes;
7864
7865
7866
7867
7868
7869
7870
7871
7872
7873
7874

7875
7876
7877
7878
7879
7880
7881
    int baseline,		/* Offset of baseline from y. */
    Display *display,		/* Display to use for drawing. */
    Drawable dst,		/* Pixmap or window in which to draw chunk. */
    int screenY)		/* Y-coordinate in text window that
				 * corresponds to y. */
{
    CharInfo *ciPtr = chunkPtr->clientData;
    const char *string;
    TextStyle *stylePtr;
    StyleValues *sValuePtr;
    int numBytes, offsetBytes, offsetX;

#if TK_DRAW_IN_CONTEXT
    BaseCharInfo *bciPtr;
#endif /* TK_DRAW_IN_CONTEXT */

    if ((x + chunkPtr->width) <= 0) {
	/*
	 * The chunk is off-screen.







|



>







7886
7887
7888
7889
7890
7891
7892
7893
7894
7895
7896
7897
7898
7899
7900
7901
7902
7903
7904
    int baseline,		/* Offset of baseline from y. */
    Display *display,		/* Display to use for drawing. */
    Drawable dst,		/* Pixmap or window in which to draw chunk. */
    int screenY)		/* Y-coordinate in text window that
				 * corresponds to y. */
{
    CharInfo *ciPtr = chunkPtr->clientData;
    char *string;
    TextStyle *stylePtr;
    StyleValues *sValuePtr;
    int numBytes, offsetBytes, offsetX;
    int ch, nBytes;
#if TK_DRAW_IN_CONTEXT
    BaseCharInfo *bciPtr;
#endif /* TK_DRAW_IN_CONTEXT */

    if ((x + chunkPtr->width) <= 0) {
	/*
	 * The chunk is off-screen.
7934
7935
7936
7937
7938
7939
7940


































7941
7942
7943
7944
7945
7946
7947
	int start = ciPtr->baseOffset + offsetBytes;
	int len = ciPtr->numBytes - offsetBytes;
	int xDisplacement = x - chunkPtr->x;

	if ((len > 0) && (string[start + len - 1] == '\t')) {
	    len--;
	}


































	if (len <= 0) {
	    return;
	}

	TkpDrawCharsInContext(display, dst, stylePtr->fgGC, sValuePtr->tkfont,
		string, numBytes, start, len,
		ciPtr->baseChunkPtr->x + xDisplacement,







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







7957
7958
7959
7960
7961
7962
7963
7964
7965
7966
7967
7968
7969
7970
7971
7972
7973
7974
7975
7976
7977
7978
7979
7980
7981
7982
7983
7984
7985
7986
7987
7988
7989
7990
7991
7992
7993
7994
7995
7996
7997
7998
7999
8000
8001
8002
8003
8004
	int start = ciPtr->baseOffset + offsetBytes;
	int len = ciPtr->numBytes - offsetBytes;
	int xDisplacement = x - chunkPtr->x;

	if ((len > 0) && (string[start + len - 1] == '\t')) {
	    len--;
	}

        /*
         * Don't draw any soft hyphen unless it is the last character
         * of the display line. Soft hyphens can only show up at the
         * end of a chunk, so test their presence at this end position
         * only.
         */

        if (chunkPtr->nextPtr != NULL) {
            nBytes = TkUtfToUniChar(Tcl_UtfPrev(string + start + len,
                    string + start), &ch);
            if (ch == 0x00AD) {
                len -= nBytes;
            }
        } else {

            /*
             * On OS X, the soft hyphen does not render (there is no
             * corresponding glyph in OS X fonts). Display a regular
             * hard hyphen instead. This could be done on all platforms
             * but for performance reasons do it only if it's needed.
             */

#ifdef MAC_OSX_TK
            nBytes = TkUtfToUniChar(Tcl_UtfPrev(string + start + len,
                    string + start), &ch);
            if (ch == 0x00AD) {
                string[start + len - nBytes] = '-';
                string[start + len - nBytes + 1] = '\0';
                len -= nBytes - 1;
            }
#endif
        }

	if (len <= 0) {
	    return;
	}

	TkpDrawCharsInContext(display, dst, stylePtr->fgGC, sValuePtr->tkfont,
		string, numBytes, start, len,
		ciPtr->baseChunkPtr->x + xDisplacement,
7968
7969
7970
7971
7972
7973
7974















































7975
7976
7977
7978
7979
7980
7981
#else /* !TK_DRAW_IN_CONTEXT */
	string += offsetBytes;
	numBytes -= offsetBytes;

	if ((numBytes > 0) && (string[numBytes - 1] == '\t')) {
	    numBytes--;
	}















































	Tk_DrawChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, string,
		numBytes, offsetX, y + baseline - sValuePtr->offset);
	if (sValuePtr->underline) {
	    Tk_UnderlineChars(display, dst, stylePtr->ulGC, sValuePtr->tkfont,
		    string, offsetX,
		    y + baseline - sValuePtr->offset,
		    0, numBytes);







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







8025
8026
8027
8028
8029
8030
8031
8032
8033
8034
8035
8036
8037
8038
8039
8040
8041
8042
8043
8044
8045
8046
8047
8048
8049
8050
8051
8052
8053
8054
8055
8056
8057
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075
8076
8077
8078
8079
8080
8081
8082
8083
8084
8085
#else /* !TK_DRAW_IN_CONTEXT */
	string += offsetBytes;
	numBytes -= offsetBytes;

	if ((numBytes > 0) && (string[numBytes - 1] == '\t')) {
	    numBytes--;
	}

        /*
         * Don't draw any soft hyphen unless it is the last character
         * of the display line. Soft hyphens can only show up at the
         * end of a chunk, so test their presence at this end position
         * only.
         * In case TK_LAYOUT_WITH_BASE_CHUNKS is true, chunkPtr needs
         * to be adjusted to point to the chunk displaying the final
         * part of the stretch, so that the test below:
         *    if (chunkPtr->nextPtr != NULL)
         * really checks whether the last character of this chunk
         * is the last character of the display line.
         */

#if TK_LAYOUT_WITH_BASE_CHUNKS
        nBytes = ciPtr->numBytes;
        while ((nBytes < numBytes) && (chunkPtr->nextPtr != NULL)) {
            chunkPtr = chunkPtr->nextPtr;
            nBytes += chunkPtr->numBytes;
        }
#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */
        if (chunkPtr->nextPtr != NULL) {
            nBytes = TkUtfToUniChar(Tcl_UtfPrev(string + numBytes, string),
                    &ch);
            if (ch == 0x00AD) {
                numBytes -= nBytes;
            }
        } else {

            /*
             * On OS X, the soft hyphen does not render (there is no
             * corresponding glyph in OS X fonts). Display a regular
             * hard hyphen instead. This could be done on all platforms
             * but for performance reasons do it only if it's needed.
             */

#ifdef MAC_OSX_TK
            nBytes = TkUtfToUniChar(Tcl_UtfPrev(string + numBytes, string),
                    &ch);
            if (ch == 0x00AD) {
                string[numBytes - nBytes] = '-';
                string[numBytes - nBytes + 1] = '\0';
                numBytes -= nBytes - 1;
            }
#endif
        }

	Tk_DrawChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, string,
		numBytes, offsetX, y + baseline - sValuePtr->offset);
	if (sValuePtr->underline) {
	    Tk_UnderlineChars(display, dst, stylePtr->ulGC, sValuePtr->tkfont,
		    string, offsetX,
		    y + baseline - sValuePtr->offset,
		    0, numBytes);
8534
8535
8536
8537
8538
8539
8540
8541
8542
8543
8544
8545
8546
8547
8548
8549
 * MeasureChars --
 *
 *	Determine the number of characters from the string that will fit in
 *	the given horizontal span. The measurement is done under the
 *	assumption that Tk_DrawChars will be used to actually display the
 *	characters.
 *
 *	If tabs are encountered in the string, they will be ignored (they
 *	should only occur as last character of the string anyway).
 *
 *	If a newline is encountered in the string, the line will be broken at
 *	that point.
 *
 * Results:
 *	The return value is the number of bytes from the range of start to end
 *	in source that fit in the span given by startX and maxX. *nextXPtr is







|
|







8638
8639
8640
8641
8642
8643
8644
8645
8646
8647
8648
8649
8650
8651
8652
8653
 * MeasureChars --
 *
 *	Determine the number of characters from the string that will fit in
 *	the given horizontal span. The measurement is done under the
 *	assumption that Tk_DrawChars will be used to actually display the
 *	characters.
 *
 *	If tabs or soft hyphens are encountered in the string, they will be
 *	ignored (they can only occur as last character of the string).
 *
 *	If a newline is encountered in the string, the line will be broken at
 *	that point.
 *
 * Results:
 *	The return value is the number of bytes from the range of start to end
 *	in source that fit in the span given by startX and maxX. *nextXPtr is
8569
8570
8571
8572
8573
8574
8575
8576
8577
8578
8579

8580
8581
8582
8583
8584
8585
8586
8587
8588
8589
8590
8591

8592
8593
8594

8595
8596
8597
8598
8599
8600
8601
				 * drawn. */
    int maxX,			/* Don't consider any character that would
				 * cross this x-position. */
    int flags,			/* Flags to pass to Tk_MeasureChars. */
    int *nextXPtr)		/* Return x-position of terminating character
				 * here. */
{
    int curX, width, ch;
    const char *special, *end, *start;

    ch = 0;			/* lint. */

    curX = startX;
    start = source + rangeStart;
    end = start + rangeLength;
    special = start;
    while (start < end) {
	if (start >= special) {
	    /*
	     * Find the next special character in the string.
	     */

	    for (special = start; special < end; special++) {
		ch = *special;

		if ((ch == '\t') || (ch == '\n')) {
		    break;
		}

	    }
	}

	/*
	 * Special points at the next special character (or the end of the
	 * string). Process characters between start and special.
	 */







|



>










|
|
>
|


>







8673
8674
8675
8676
8677
8678
8679
8680
8681
8682
8683
8684
8685
8686
8687
8688
8689
8690
8691
8692
8693
8694
8695
8696
8697
8698
8699
8700
8701
8702
8703
8704
8705
8706
8707
8708
				 * drawn. */
    int maxX,			/* Don't consider any character that would
				 * cross this x-position. */
    int flags,			/* Flags to pass to Tk_MeasureChars. */
    int *nextXPtr)		/* Return x-position of terminating character
				 * here. */
{
    int curX, width, ch, nBytes;
    const char *special, *end, *start;

    ch = 0;			/* lint. */
    nBytes = 0;			/* Silence compiler warning. */
    curX = startX;
    start = source + rangeStart;
    end = start + rangeLength;
    special = start;
    while (start < end) {
	if (start >= special) {
	    /*
	     * Find the next special character in the string.
	     */

	    special = start;
            while (special < end) {
		nBytes = TkUtfToUniChar(special, &ch);
		if ((ch == 0x09) || (ch == 0x0A) || (ch == 0x00AD)) {
		    break;
		}
                special += nBytes;
	    }
	}

	/*
	 * Special points at the next special character (or the end of the
	 * string). Process characters between start and special.
	 */
8617
8618
8619
8620
8621
8622
8623
8624
8625
8626



8627

8628
8629
8630
8631
8632
8633
8634
	    /*
	     * No more chars fit in line.
	     */

	    break;
	}
	if (special < end) {
	    if (ch != '\t') {
		break;
	    }



	    start++;

	}
    }

    *nextXPtr = curX;
    return start - (source+rangeStart);
}








|


>
>
>
|
>







8724
8725
8726
8727
8728
8729
8730
8731
8732
8733
8734
8735
8736
8737
8738
8739
8740
8741
8742
8743
8744
8745
	    /*
	     * No more chars fit in line.
	     */

	    break;
	}
	if (special < end) {
	    if (ch == 0x0A) {
		break;
	    }
            if (ch == 0x00AD) {
                start += nBytes;
            } else {
	        start++;
            }
	}
    }

    *nextXPtr = curX;
    return start - (source+rangeStart);
}


Changes to macosx/tkMacOSXFont.c.

872
873
874
875
876
877
878










879
880
881
882
883
884
885
	}
	cs = (index <= len && (flags & TK_WHOLE_WORDS)) ?
		whitespaceCharacterSet : lineendingCharacterSet;
	while (index > start &&
		[cs characterIsMember:[string characterAtIndex:(index - 1)]]) {
	    index--;
	}










	if (index <= start && (flags & TK_AT_LEAST_ONE)) {
	    index = start + 1;
	}
	if (index > 0) {
	    range.length = index;
	    line = CTTypesetterCreateLine(typesetter, range);
	    width = CTLineGetTypographicBounds(line, NULL, NULL, NULL);







>
>
>
>
>
>
>
>
>
>







872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
	}
	cs = (index <= len && (flags & TK_WHOLE_WORDS)) ?
		whitespaceCharacterSet : lineendingCharacterSet;
	while (index > start &&
		[cs characterIsMember:[string characterAtIndex:(index - 1)]]) {
	    index--;
	}

        /*
         * CTTypesetterSuggestClusterBreak et al. above may return an index
         * larger than the end of the range to consider. Limit to given end.
         */

        if (index > start + len) {
            index = start + len;
        }

	if (index <= start && (flags & TK_AT_LEAST_ONE)) {
	    index = start + 1;
	}
	if (index > 0) {
	    range.length = index;
	    line = CTTypesetterCreateLine(typesetter, range);
	    width = CTLineGetTypographicBounds(line, NULL, NULL, NULL);

Changes to tests/textDisp.test.

516
517
518
519
520
521
522



























































523
524
525
526
527
528
529
    .t bbox 1.4
} [list 117 5 7 $fixedHeight]
test textDisp-2.30 {LayoutDLine, tabs, running out of space in dline} {textfonts} {
    .t delete 1.0 end
    .t insert 1.0 "a\tx\tabc"
    .t bbox 1.4
} [list 117 5 7 $fixedHeight]




























































test textDisp-3.1 {different character sizes} {textfonts} {
    .t configure -wrap word
    .t delete 1.0 end
    .t insert end "Some sample text, including both large\n"
    .t insert end "characters and\nsmall\n"
    .t insert end "abc\nd\ne\nfghij"







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







516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
    .t bbox 1.4
} [list 117 5 7 $fixedHeight]
test textDisp-2.30 {LayoutDLine, tabs, running out of space in dline} {textfonts} {
    .t delete 1.0 end
    .t insert 1.0 "a\tx\tabc"
    .t bbox 1.4
} [list 117 5 7 $fixedHeight]
test textDisp-2.31 {LayoutDLine, word wrap on ordinary hyphen} {textfonts} {
    .t delete 1.0 end
    .t insert 1.0 "This is a *normal* hyphen  test: abc-123\n"
    # test robustness: we only want to check that line wrapped at the hyphen, i.e.
    # that the hyphen is still on the second display line while "123" is on the
    # third one - check exactly this and not, say, a bbox
    .t sync
    list [.t count -displaylines 1.0 1.36] [.t count -displaylines 1.36 1.37]
} [list 1 1]
test textDisp-2.32 {LayoutDLine, word wrap on soft hyphen} {textfonts} {
    .t delete 1.0 end
    .t insert 1.0 "This is a  -*soft*-  hyphen   test: abc\u00AD123\n"
    # test robustness: we only want to check that line wrapped at the hyphen, i.e.
    # that the hyphen is still on the second display line while "123" is on the
    # third one - check exactly this and not, say, a bbox
    .t sync
    list [.t count -displaylines 1.0 1.39] [.t count -displaylines 1.39 1.40]
} [list 1 1]
test textDisp-2.33 {soft hyphen is not visible when not at display line end} {textfonts} {
    .t delete 1.0 end
    .t insert 1.0 "\u00ADSoft\u00AD\u00AD\u00ADhyphen test.\nAgain!\u00AD"
    set res [lindex [.t bbox 1.0] 2]
    lappend res [expr [lindex [.t bbox 1.1] 2] > 0 ]
    lappend res [lindex [.t bbox 1.5] 2]
    lappend res [lindex [.t bbox 1.6] 2]
    lappend res [lindex [.t bbox 1.7] 2]
    lappend res [expr [lindex [.t bbox 1.8] 2] > 0 ]
    lappend res [lindex [.t bbox 2.6] 2]
} [list 0 1 0 0 0 1 0]
test textDisp-2.34 {soft hyphen is visible when at display line end} {textfonts} {
    .t delete 1.0 end
    .t insert 1.0 "This is a  -*soft*-  hyphen   test: abc\u00AD123\n"
    # soft hyphens always have zero width in their bounding boxes,
    # even if they are accidentally displayed
    set res [expr [lindex [.t bbox 1.39] 2] == 0]
} {1}
test textDisp-2.35 {LayoutDline, maxBytes calculation for chunk with both soft hyphen and tab} {textfonts} {
    .t delete 1.0 end
    .t insert end "Test\twith soft\u00ADhyphen and\ttabs.\n"
    .t insert end "Test\u00ADwith soft\thyphen and\u00ADtabs.\n"
    set res [expr [lindex [.t bbox 1.4] 2] > 0]
    lappend res [lindex [.t bbox 1.14] 2]
    lappend res [expr [lindex [.t bbox 1.25] 2] > 0]
    lappend res [lindex [.t bbox 2.4] 2]
    lappend res [expr [lindex [.t bbox 2.14] 2] > 0]
    lappend res [lindex [.t bbox 2.25] 2]
} [list 1 0 1 0 1 0]
test textDisp-2.36 {a soft hyphen counts for 1 char even if not visible} {textfonts} {
    .t delete 1.0 end
    .t insert 1.0 "\u00ADSoft\u00AD\u00AD\u00ADhyphen test."
    set res [.t count -chars 1.0 1.14]
    lappend res [.t count -displaychars 1.0 1.14]
    lappend res [.t count -indices 1.0 1.14]
    lappend res [.t count -displayindices 1.0 1.14]
    # All the above results must be same. With or without the "display" modifier
    # makes no difference: despite not being visible the soft hyphens are not
    # *elided* (i.e. not tagged as elided). In other words soft hyphens are
    # displayed and count for 1 char each, but with zero width
} [list 14 14 14 14]

test textDisp-3.1 {different character sizes} {textfonts} {
    .t configure -wrap word
    .t delete 1.0 end
    .t insert end "Some sample text, including both large\n"
    .t insert end "characters and\nsmall\n"
    .t insert end "abc\nd\ne\nfghij"

Changes to win/tkWinFont.c.

952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
    }

    SelectObject(hdc, oldFont);
    ReleaseDC(fontPtr->hwnd, hdc);

    if ((flags & TK_WHOLE_WORDS) && (p < end)) {
	/*
	 * Scan the string for the last word break and than repeat the whole
	 * procedure without the maxLength limit or any flags.
	 */

	const char *lastWordBreak = NULL;
	int ch2;

	end = p;







|







952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
    }

    SelectObject(hdc, oldFont);
    ReleaseDC(fontPtr->hwnd, hdc);

    if ((flags & TK_WHOLE_WORDS) && (p < end)) {
	/*
	 * Scan the string for the last word break and then repeat the whole
	 * procedure without the maxLength limit or any flags.
	 */

	const char *lastWordBreak = NULL;
	int ch2;

	end = p;