Tk Source Code

Check-in Differences
Login

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

Difference From 5ff8c90caff4d615 To 7d11da38b1366d28

2016-09-29
12:03
Fix [6c0d7aec67]: unicode text input Windows 8. Added some test-cases using the "font actual" command. check-in: 3c1d50b0 user: jan.nijtmans tags: core-8-6-branch
2016-09-28
15:54
Fixed [1082213fff] - word wrapping should trim excess spaces check-in: 69686423 user: fvogel tags: bug-1082213fff
2016-09-27
15:50
merge core-8-6-branch, keep FONTMAP_SHIFT to the original value. Closed-Leaf check-in: 7d11da38 user: jan.nijtmans tags: rfe-6c0d7aec67
15:44
clearify comment check-in: 5ff8c90c user: jan.nijtmans tags: core-8-6-branch
15:21
Merge core-8-6-branch. More surrogate handling, e.g. in HandleIMEComposition() check-in: 9e7c5fd0 user: jan.nijtmans tags: rfe-6c0d7aec67
14:41
Internal code simplification: Store Unicode character in keycode field in stead of trans_chars. No behavior change, just use a different internal event type. check-in: 9cd5169a user: jan.nijtmans tags: core-8-6-branch

Changes to generic/tkEntry.c.

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
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







-
-
+
+









-
-
+
+








    /*
     * If we're displaying a special character instead of the value of the
     * entry, recompute the displayString.
     */

    if (entryPtr->showChar != NULL) {
	Tcl_UniChar ch;
	char buf[TCL_UTF_MAX];
	int ch;
	char buf[6];
	int size;

	/*
	 * Normalize the special character so we can safely duplicate it in
	 * the display string. If we didn't do this, then two malformed
	 * characters might end up looking like one valid UTF character in the
	 * resulting string.
	 */

	Tcl_UtfToUniChar(entryPtr->showChar, &ch);
	size = Tcl_UniCharToUtf(ch, buf);
	TkUtfToUniChar(entryPtr->showChar, &ch);
	size = TkUniCharToUtf(ch, buf);

	entryPtr->numDisplayBytes = entryPtr->numChars * size;
	p = ckalloc(entryPtr->numDisplayBytes + 1);
	entryPtr->displayString = p;

	for (i = entryPtr->numChars; --i >= 0; ) {
	    memcpy(p, buf, size);
3408
3409
3410
3411
3412
3413
3414
3415

3416
3417
3418
3419
3420
3421
3422
3408
3409
3410
3411
3412
3413
3414

3415
3416
3417
3418
3419
3420
3421
3422







-
+







     Tcl_DString *dsPtr)	/* Dynamic string in which to append new
				 * command. */
{
    int spaceNeeded, cvtFlags;	/* Used to substitute string as proper Tcl
				 * list element. */
    int number, length;
    register const char *string;
    Tcl_UniChar ch;
    int ch;
    char numStorage[2*TCL_INTEGER_SPACE];

    while (1) {
	if (*before == '\0') {
	    break;
	}
	/*
3441
3442
3443
3444
3445
3446
3447
3448

3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468

3469
3470
3471
3472
3473
3474
3475
3441
3442
3443
3444
3445
3446
3447

3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467

3468
3469
3470
3471
3472
3473
3474
3475







-
+



















-
+








	/*
	 * There's a percent sequence here. Process it.
	 */

	before++; /* skip over % */
	if (*before != '\0') {
	    before += Tcl_UtfToUniChar(before, &ch);
	    before += TkUtfToUniChar(before, &ch);
	} else {
	    ch = '%';
	}
	if (type == VALIDATE_BUTTON) {
	    /*
	     * -command %-substitution
	     */

	    switch (ch) {
	    case 's':		/* Current string value of spinbox */
		string = entryPtr->string;
		break;
	    case 'd':		/* direction, up or down */
		string = change;
		break;
	    case 'W':		/* widget name */
		string = Tk_PathName(entryPtr->tkwin);
		break;
	    default:
		length = Tcl_UniCharToUtf(ch, numStorage);
		length = TkUniCharToUtf(ch, numStorage);
		numStorage[length] = '\0';
		string = numStorage;
		break;
	    }
	} else {
	    /*
	     * -validatecommand / -invalidcommand %-substitution
3521
3522
3523
3524
3525
3526
3527
3528

3529
3530
3531
3532
3533
3534
3535
3521
3522
3523
3524
3525
3526
3527

3528
3529
3530
3531
3532
3533
3534
3535







-
+







		    break;
		}
		break;
	    case 'W': /* widget name */
		string = Tk_PathName(entryPtr->tkwin);
		break;
	    default:
		length = Tcl_UniCharToUtf(ch, numStorage);
		length = TkUniCharToUtf(ch, numStorage);
		numStorage[length] = '\0';
		string = numStorage;
		break;
	    }
	}

	spaceNeeded = Tcl_ScanCountedElement(string, -1, &cvtFlags);

Changes to generic/tkFont.c.

493
494
495
496
497
498
499
500

501
502
503
504
505
506
507
493
494
495
496
497
498
499

500
501
502
503
504
505
506
507







-
+








    switch ((enum options) index) {
    case FONT_ACTUAL: {
	int skip, result, n;
	const char *s;
	Tk_Font tkfont;
	Tcl_Obj *optPtr, *charPtr, *resultPtr;
	Tcl_UniChar uniChar = 0;
	int uniChar = 0;
	const TkFontAttributes *faPtr;
	TkFontAttributes fa;

	/*
	 * Params 0 and 1 are 'font actual'. Param 2 is the font name. 3-4 may
	 * be '-displayof $window'
	 */
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
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







+
+
-
+
+


-
+






-







	}

	/*
	 * The 'charPtr' arg must be a single Unicode.
	 */

	if (charPtr != NULL) {
	    const char *string = Tcl_GetString(charPtr);
	    int len = TkUtfToUniChar(string, &uniChar);
	    if (Tcl_GetCharLength(charPtr) != 1) {

	    if (len != charPtr->length) {
		resultPtr = Tcl_NewStringObj(
			"expected a single character but got \"", -1);
		Tcl_AppendLimitedToObj(resultPtr, Tcl_GetString(charPtr),
		Tcl_AppendLimitedToObj(resultPtr, string,
			-1, 40, "...");
		Tcl_AppendToObj(resultPtr, "\"", -1);
		Tcl_SetObjResult(interp, resultPtr);
		Tcl_SetErrorCode(interp, "TK", "VALUE", "FONT_SAMPLE", NULL);
		return TCL_ERROR;
	    }
	    uniChar = Tcl_GetUniChar(charPtr, 0);
	}

	/*
	 * Find the font.
	 */

	tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
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
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







-
+

















-
+






-
+







    } else if (strcasecmp(family, "AvantGarde") == 0) {
	family = "AvantGarde";
    } else if (strcasecmp(family, "ZapfChancery") == 0) {
	family = "ZapfChancery";
    } else if (strcasecmp(family, "ZapfDingbats") == 0) {
	family = "ZapfDingbats";
    } else {
	Tcl_UniChar ch;
	int ch;

	/*
	 * Inline, capitalize the first letter of each word, lowercase the
	 * rest of the letters in each word, and then take out the spaces
	 * between the words. This may make the DString shorter, which is safe
	 * to do.
	 */

	Tcl_DStringAppend(dsPtr, family, -1);

	src = dest = Tcl_DStringValue(dsPtr) + len;
	upper = 1;
	for (; *src != '\0'; ) {
	    while (isspace(UCHAR(*src))) { /* INTL: ISO space */
		src++;
		upper = 1;
	    }
	    src += Tcl_UtfToUniChar(src, &ch);
	    src += TkUtfToUniChar(src, &ch);
	    if (upper) {
		ch = Tcl_UniCharToUpper(ch);
		upper = 0;
	    } else {
		ch = Tcl_UniCharToLower(ch);
	    }
	    dest += Tcl_UniCharToUtf(ch, dest);
	    dest += TkUniCharToUtf(ch, dest);
	}
	*dest = '\0';
	Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr));
	family = Tcl_DStringValue(dsPtr) + len;
    }
    if (family != Tcl_DStringValue(dsPtr) + len) {
	Tcl_DStringAppend(dsPtr, family, -1);
3245
3246
3247
3248
3249
3250
3251
3252

3253
3254
3255
3256
3257
3258
3259
3247
3248
3249
3250
3251
3252
3253

3254
3255
3256
3257
3258
3259
3260
3261







-
+







    TextLayout *layoutPtr = (TextLayout *) layout;
    LayoutChunk *chunkPtr = layoutPtr->chunks;
    int baseline = chunkPtr->y;
    Tcl_Obj *psObj = Tcl_NewObj();
    int i, j, len;
    const char *p, *glyphname;
    char uindex[5], c, *ps;
    Tcl_UniChar ch;
    int ch;

    Tcl_AppendToObj(psObj, "[(", -1);
    for (i = 0; i < layoutPtr->numChunks; i++, chunkPtr++) {
	if (baseline != chunkPtr->y) {
	    Tcl_AppendToObj(psObj, ")]\n[(", -1);
	    baseline = chunkPtr->y;
	}
3268
3269
3270
3271
3272
3273
3274
3275

3276
3277
3278
3279
3280
3281
3282
3270
3271
3272
3273
3274
3275
3276

3277
3278
3279
3280
3281
3282
3283
3284







-
+







	    /*
	     * INTL: We only handle symbols that have an encoding as a glyph
	     * from the standard set defined by Adobe. The rest get punted.
	     * Eventually this should be revised to handle more sophsticiated
	     * international postscript fonts.
	     */

	    p += Tcl_UtfToUniChar(p, &ch);
	    p += TkUtfToUniChar(p, &ch);
	    if ((ch == '(') || (ch == ')') || (ch == '\\') || (ch < 0x20)) {
		/*
		 * Tricky point: the "03" is necessary in the sprintf below,
		 * so that a full three digits of octal are always generated.
		 * Without the "03", a number following this sequence could be
		 * interpreted by Postscript as part of this sequence.
		 */
3294
3295
3296
3297
3298
3299
3300



3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320

3321
3322
3323
3324
3325
3326
3327
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333







+
+
+




















+







	    }

	    /*
	     * This character doesn't belong to the ASCII character set, so we
	     * use the full glyph name.
	     */

	    if (ch > 0xffff) {
		goto noMapping;
	    }
	    sprintf(uindex, "%04X", ch);		/* endianness? */
	    glyphname = Tcl_GetVar2(interp, "::tk::psglyphs", uindex, 0);
	    if (glyphname) {
		ps = Tcl_GetStringFromObj(psObj, &len);
		if (ps[len-1] == '(') {
		    /*
		     * In-place edit. Ewww!
		     */

		    ps[len-1] = '/';
		} else {
		    Tcl_AppendToObj(psObj, ")/", -1);
		}
		Tcl_AppendToObj(psObj, glyphname, -1);
		Tcl_AppendToObj(psObj, "(", -1);
	    } else {
		/*
		 * No known mapping for the character into the space of
		 * PostScript glyphs. Ignore it. :-(
		 */
noMapping:	;

#ifdef TK_DEBUG_POSTSCRIPT_OUTPUT
		fprintf(stderr, "Warning: no mapping to PostScript "
			"glyphs for \\u%04x\n", ch);
#endif
	    }
	}

Changes to generic/tkText.c.

4455
4456
4457
4458
4459
4460
4461
4462

4463
4464
4465
4466
4467
4468
4469
4455
4456
4457
4458
4459
4460
4461

4462
4463
4464
4465
4466
4467
4468
4469







-
+







    Tcl_Obj *stringPtr)		/* Description of the tab stops. See the text
				 * manual entry for details. */
{
    int objc, i, count;
    Tcl_Obj **objv;
    TkTextTabArray *tabArrayPtr;
    TkTextTab *tabPtr;
    Tcl_UniChar ch;
    int ch;
    double prevStop, lastStop;
    /*
     * Map these strings to TkTextTabAlign values.
     */
    static const char *const tabOptionStrings[] = {
	"left", "right", "center", "numeric", NULL
    };
4562
4563
4564
4565
4566
4567
4568
4569

4570
4571
4572
4573
4574
4575
4576
4562
4563
4564
4565
4566
4567
4568

4569
4570
4571
4572
4573
4574
4575
4576







-
+







	    continue;
	}

	/*
	 * There may be a more efficient way of getting this.
	 */

	Tcl_UtfToUniChar(Tcl_GetString(objv[i+1]), &ch);
	TkUtfToUniChar(Tcl_GetString(objv[i+1]), &ch);
	if (!Tcl_UniCharIsAlpha(ch)) {
	    continue;
	}
	i += 1;

	if (Tcl_GetIndexFromObjStruct(interp, objv[i], tabOptionStrings,
		sizeof(char *), "tab alignment", 0, &index) != TCL_OK) {
5876
5877
5878
5879
5880
5881
5882
5883

5884
5885
5886
5887
5888
5889
5890
5876
5877
5878
5879
5880
5881
5882

5883
5884
5885
5886
5887
5888
5889
5890







-
+








	if (searchSpecPtr->exact) {
	    int maxExtraLines = 0;
	    const char *startOfLine = Tcl_GetString(theLine);

	    CLANG_ASSERT(pattern);
	    do {
		Tcl_UniChar ch;
		int ch;
		const char *p;
		int lastFullLine = lastOffset;

		if (firstNewLine == -1) {
		    if (searchSpecPtr->strictLimits
			    && (firstOffset + matchLength > lastOffset)) {
			/*
6106
6107
6108
6109
6110
6111
6112
6113

6114
6115
6116
6117
6118
6119
6120
6106
6107
6108
6109
6110
6111
6112

6113
6114
6115
6116
6117
6118
6119
6120







-
+







		    if (searchSpecPtr->backwards) {
			alreadySearchOffset = p - startOfLine - 1;
			if (alreadySearchOffset < 0) {
			    break;
			}
		    } else {
			firstOffset = p - startOfLine +
				Tcl_UtfToUniChar(startOfLine+matchOffset,&ch);
				TkUtfToUniChar(startOfLine+matchOffset,&ch);
		    }
		}
	    } while (searchSpecPtr->all);
	} else {
	    int maxExtraLines = 0;
	    int matches = 0;
	    int lastNonOverlap = -1;

Changes to generic/tkTextDisp.c.

7577
7578
7579
7580
7581
7582
7583
7584
7585


7586
7587
7588
7589
7590
7591
7592
7577
7578
7579
7580
7581
7582
7583


7584
7585
7586
7587
7588
7589
7590
7591
7592







-
-
+
+







#else /* !TK_LAYOUT_WITH_BASE_CHUNKS */
    bytesThatFit = CharChunkMeasureChars(chunkPtr, p, maxBytes, 0, -1,
	    chunkPtr->x, maxX, TK_ISOLATE_END, &nextX);
#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */

    if (bytesThatFit < maxBytes) {
	if ((bytesThatFit == 0) && noCharsYet) {
	    Tcl_UniChar ch;
	    int chLen = Tcl_UtfToUniChar(p, &ch);
	    int ch;
	    int chLen = TkUtfToUniChar(p, &ch);

#if TK_LAYOUT_WITH_BASE_CHUNKS
	    bytesThatFit = CharChunkMeasureChars(chunkPtr, line,
		    lineOffset+chLen, lineOffset, -1, chunkPtr->x, -1, 0,
		    &nextX);
#else /* !TK_LAYOUT_WITH_BASE_CHUNKS */
	    bytesThatFit = CharChunkMeasureChars(chunkPtr, p, chLen, 0, -1,

Changes to generic/tkTextIndex.c.

2294
2295
2296
2297
2298
2299
2300
2301

2302
2303

2304
2305
2306
2307
2308
2309
2310
2294
2295
2296
2297
2298
2299
2300

2301
2302

2303
2304
2305
2306
2307
2308
2309
2310







-
+

-
+







		    COUNT_DISPLAY_INDICES);
	}
	segPtr = TkTextIndexToSeg(indexPtr, &offset);
	while (1) {
	    int chSize = 1;

	    if (segPtr->typePtr == &tkTextCharType) {
		Tcl_UniChar ch;
		int ch;

		chSize = Tcl_UtfToUniChar(segPtr->body.chars + offset, &ch);
		chSize = TkUtfToUniChar(segPtr->body.chars + offset, &ch);
		if (!Tcl_UniCharIsWordChar(ch)) {
		    break;
		}
		firstChar = 0;
	    }
	    offset += chSize;
	    indexPtr->byteIndex += chSize;
2339
2340
2341
2342
2343
2344
2345
2346
2347

2348

2349
2350
2351
2352
2353
2354
2355
2339
2340
2341
2342
2343
2344
2345

2346
2347

2348
2349
2350
2351
2352
2353
2354
2355







-

+
-
+







	 */

	segPtr = TkTextIndexToSeg(indexPtr, &offset);
	while (1) {
	    int chSize = 1;

	    if (segPtr->typePtr == &tkTextCharType) {
		Tcl_UniChar ch;

		int ch;
		Tcl_UtfToUniChar(segPtr->body.chars + offset, &ch);
		TkUtfToUniChar(segPtr->body.chars + offset, &ch);
		if (!Tcl_UniCharIsWordChar(ch)) {
		    break;
		}
		if (offset > 0) {
		    chSize = (segPtr->body.chars + offset
			    - Tcl_UtfPrev(segPtr->body.chars + offset,
			    segPtr->body.chars));

Changes to generic/ttk/ttkEntry.c.

278
279
280
281
282
283
284
285
286


287
288
289


290
291
292
293
294
295
296
278
279
280
281
282
283
284


285
286
287


288
289
290
291
292
293
294
295
296







-
-
+
+

-
-
+
+







 * 	of (the first character in the string) 'showChar'.
 * 	Used to compute the displayString if -show is non-NULL.
 */
static char *EntryDisplayString(const char *showChar, int numChars)
{
    char *displayString, *p;
    int size;
    Tcl_UniChar ch;
    char buf[TCL_UTF_MAX];
    int ch;
    char buf[6];

    Tcl_UtfToUniChar(showChar, &ch);
    size = Tcl_UniCharToUtf(ch, buf);
    TkUtfToUniChar(showChar, &ch);
    size = TkUniCharToUtf(ch, buf);
    p = displayString = ckalloc(numChars * size + 1);

    while (numChars--) {
	memcpy(p, buf, size);
	p += size;
    }
    *p = '\0';
402
403
404
405
406
407
408
409

410
411
412
413
414
415
416
402
403
404
405
406
407
408

409
410
411
412
413
414
415
416







-
+







     VREASON reason,		/* Reason for change */
     Tcl_DString *dsPtr)	/* Result of %-substitutions */
{
    int spaceNeeded, cvtFlags;
    int number, length;
    const char *string;
    int stringLength;
    Tcl_UniChar ch;
    int ch;
    char numStorage[2*TCL_INTEGER_SPACE];

    while (*template) {
	/* Find everything up to the next % character and append it
	 * to the result string.
	 */
	string = Tcl_UtfFindFirst(template, '%');
426
427
428
429
430
431
432
433

434
435
436
437
438
439
440
426
427
428
429
430
431
432

433
434
435
436
437
438
439
440







-
+







	    template = string;
	}

	/* There's a percent sequence here.  Process it.
	 */
	++template; /* skip over % */
	if (*template != '\0') {
	    template += Tcl_UtfToUniChar(template, &ch);
	    template += TkUtfToUniChar(template, &ch);
	} else {
	    ch = '%';
	}

	stringLength = -1;
	switch (ch) {
	    case 'd': /* Type of call that caused validation */
476
477
478
479
480
481
482
483

484
485
486
487
488
489
490
476
477
478
479
480
481
482

483
484
485
486
487
488
489
490







-
+







	    case 'V': /* type of validation in effect */
		string = validateReasonStrings[reason];
		break;
	    case 'W': /* widget name */
		string = Tk_PathName(entryPtr->core.tkwin);
		break;
	    default:
		length = Tcl_UniCharToUtf(ch, numStorage);
		length = TkUniCharToUtf(ch, numStorage);
		numStorage[length] = '\0';
		string = numStorage;
		break;
	}

	spaceNeeded = Tcl_ScanCountedElement(string, stringLength, &cvtFlags);
	length = Tcl_DStringLength(dsPtr);

Changes to unix/tkUnixFont.c.

402
403
404
405
406
407
408
409

410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430

431
432

433
434
435
436
437
438
439
440

441
442
443
444
445
446








447
448
449
450
451
452
453
402
403
404
405
406
407
408

409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429

430
431

432
433
434
435
436
437
438
439

440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461







-
+




















-
+

-
+







-
+






+
+
+
+
+
+
+
+







				 * the conversion. */
    int *dstCharsPtr)		/* Filled with the number of characters that
				 * correspond to the bytes stored in the
				 * output buffer. */
{
    const char *srcStart, *srcEnd;
    char *dstStart, *dstEnd;
    Tcl_UniChar ch;
    int ch;
    int result;
    static char hexChars[] = "0123456789abcdef";
    static char mapChars[] = {
	0, 0, 0, 0, 0, 0, 0,
	'a', 'b', 't', 'n', 'v', 'f', 'r'
    };

    result = TCL_OK;

    srcStart = src;
    srcEnd = src + srcLen;

    dstStart = dst;
    dstEnd = dst + dstLen - 6;

    for ( ; src < srcEnd; ) {
	if (dst > dstEnd) {
	    result = TCL_CONVERT_NOSPACE;
	    break;
	}
	src += Tcl_UtfToUniChar(src, &ch);
	src += TkUtfToUniChar(src, &ch);
	dst[0] = '\\';
	if ((ch < sizeof(mapChars)) && (mapChars[ch] != 0)) {
	if (((size_t) ch < sizeof(mapChars)) && (mapChars[ch] != 0)) {
	    dst[1] = mapChars[ch];
	    dst += 2;
	} else if (ch < 256) {
	    dst[1] = 'x';
	    dst[2] = hexChars[(ch >> 4) & 0xf];
	    dst[3] = hexChars[ch & 0xf];
	    dst += 4;
	} else {
	} else if (ch < 0x10000) {
	    dst[1] = 'u';
	    dst[2] = hexChars[(ch >> 12) & 0xf];
	    dst[3] = hexChars[(ch >> 8) & 0xf];
	    dst[4] = hexChars[(ch >> 4) & 0xf];
	    dst[5] = hexChars[ch & 0xf];
	    dst += 6;
	} else {
	    /* TODO we can do better here */
	    dst[1] = 'u';
	    dst[2] = 'f';
	    dst[3] = 'f';
	    dst[4] = 'f';
	    dst[5] = 'd';
	    dst += 6;
	}
    }
    *srcReadPtr = src - srcStart;
    *dstWrotePtr = dst - dstStart;
    *dstCharsPtr = dst - dstStart;
    return result;
}
1024
1025
1026
1027
1028
1029
1030
1031

1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047

1048
1049
1050
1051
1052
1053
1054
1032
1033
1034
1035
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







-
+















-
+







    lastSubFontPtr = &fontPtr->subFontArray[0];

    if (numBytes == 0) {
	curX = 0;
	curByte = 0;
    } else if (maxLength < 0) {
	const char *p, *end, *next;
	Tcl_UniChar ch;
	int ch;
	SubFont *thisSubFontPtr;
	FontFamily *familyPtr;
	Tcl_DString runString;

	/*
	 * A three step process:
	 * 1. Find a contiguous range of characters that can all be
	 *    represented by a single screen font.
	 * 2. Convert those chars to the encoding of that font.
	 * 3. Measure converted chars.
	 */

	curX = 0;
	end = source + numBytes;
	for (p = source; p < end; ) {
	    next = p + Tcl_UtfToUniChar(p, &ch);
	    next = p + TkUtfToUniChar(p, &ch);
	    thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
	    if (thisSubFontPtr != lastSubFontPtr) {
		familyPtr = lastSubFontPtr->familyPtr;
		Tcl_UtfToExternalDString(familyPtr->encoding, source,
			p - source, &runString);
		if (familyPtr->isTwoByteFont) {
		    curX += XTextWidth16(lastSubFontPtr->fontStructPtr,

Changes to unix/tkUnixRFont.c.

664
665
666
667
668
669
670
671

672
673

674
675
676
677
678
679
680
664
665
666
667
668
669
670

671
672

673
674
675
676
677
678
679
680







-
+

-
+







    int len = 0;
#endif /* DEBUG_FONTSEL */

    curX = 0;
    curByte = 0;
    sawNonSpace = 0;
    while (numBytes > 0) {
	Tcl_UniChar unichar;
	int unichar;

	clen = Tcl_UtfToUniChar(source, &unichar);
	clen = TkUtfToUniChar(source, &unichar);
	c = (FcChar32) unichar;

	if (clen <= 0) {
	    /*
	     * This can't happen (but see #1185640)
	     */

Changes to win/tkWinFont.c.

824
825
826
827
828
829
830
831

832
833
834
835
836
837
838
824
825
826
827
828
829
830

831
832
833
834
835
836
837
838







-
+







    int *lengthPtr)		/* Filled with x-location just after the
				 * terminating character. */
{
    HDC hdc;
    HFONT oldFont;
    WinFont *fontPtr;
    int curX, moretomeasure;
    Tcl_UniChar ch;
    int ch;
    SIZE size;
    FontFamily *familyPtr;
    Tcl_DString runString;
    SubFont *thisSubFontPtr, *lastSubFontPtr;
    const char *p, *end, *next = NULL, *start;

    if (numBytes == 0) {
855
856
857
858
859
860
861
862

863
864
865
866
867
868
869
855
856
857
858
859
860
861

862
863
864
865
866
867
868
869







-
+







     */

    moretomeasure = 0;
    curX = 0;
    start = source;
    end = start + numBytes;
    for (p = start; p < end; ) {
	next = p + Tcl_UtfToUniChar(p, &ch);
	next = p + TkUtfToUniChar(p, &ch);
	thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
	if (thisSubFontPtr != lastSubFontPtr) {
	    familyPtr = lastSubFontPtr->familyPtr;
	    Tcl_UtfToExternalDString(familyPtr->encoding, start,
		    (int) (p - start), &runString);
	    size.cx = 0;
	    familyPtr->getTextExtentPoint32Proc(hdc,
917
918
919
920
921
922
923
924

925
926
927
928
929
930
931
917
918
919
920
921
922
923

924
925
926
927
928
929
930
931







-
+







	char buf[16];
	int dstWrote;
	int lastSize = 0;

	familyPtr = lastSubFontPtr->familyPtr;
	Tcl_DStringInit(&runString);
	for (p = start; p < end; ) {
	    next = p + Tcl_UtfToUniChar(p, &ch);
	    next = p + TkUtfToUniChar(p, &ch);
	    Tcl_UtfToExternal(NULL, familyPtr->encoding, p,
		    (int) (next - p), 0, NULL, buf, sizeof(buf), NULL,
		    &dstWrote, NULL);
	    Tcl_DStringAppend(&runString,buf,dstWrote);
	    size.cx = 0;
	    familyPtr->getTextExtentPoint32Proc(hdc,
		    (TCHAR *) Tcl_DStringValue(&runString),
966
967
968
969
970
971
972
973

974
975
976
977
978
979

980
981
982
983
984
985
986
966
967
968
969
970
971
972

973
974
975
976
977
978

979
980
981
982
983
984
985
986







-
+





-
+







    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;
	Tcl_UniChar ch2;
	int ch2;

	end = p;
	p = source;
	ch = ' ';
	while (p < end) {
	    next = p + Tcl_UtfToUniChar(p, &ch2);
	    next = p + TkUtfToUniChar(p, &ch2);
	    if ((ch != ' ') && (ch2 == ' ')) {
		lastWordBreak = p;
	    }
	    p = next;
	    ch = ch2;
	}

1439
1440
1441
1442
1443
1444
1445
1446

1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461

1462
1463
1464
1465
1466
1467
1468
1439
1440
1441
1442
1443
1444
1445

1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460

1461
1462
1463
1464
1465
1466
1467
1468







-
+














-
+







				 * following string. */
    const char *source,		/* Potentially multilingual UTF-8 string. */
    int numBytes,		/* Length of string in bytes. */
    int x, int y,		/* Coordinates at which to place origin of
				 * string when drawing. */
    double angle)
{
    Tcl_UniChar ch;
    int ch;
    SIZE size;
    HFONT oldFont;
    FontFamily *familyPtr;
    Tcl_DString runString;
    const char *p, *end, *next;
    SubFont *lastSubFontPtr, *thisSubFontPtr;
    TEXTMETRICA tm;

    lastSubFontPtr = &fontPtr->subFontArray[0];
    oldFont = SelectFont(hdc, fontPtr, lastSubFontPtr, angle);
    GetTextMetricsA(hdc, &tm);

    end = source + numBytes;
    for (p = source; p < end; ) {
	next = p + Tcl_UtfToUniChar(p, &ch);
	next = p + TkUtfToUniChar(p, &ch);
	thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
	if (thisSubFontPtr != lastSubFontPtr) {
	    if (p > source) {
		familyPtr = lastSubFontPtr->familyPtr;
 		Tcl_UtfToExternalDString(familyPtr->encoding, source,
			(int) (p - source), &runString);
		familyPtr->textOutProc(hdc, x-(tm.tmOverhang/2), y,

Changes to win/tkWinX.c.

1522
1523
1524
1525
1526
1527
1528
1529

1530
1531
1532
1533
1534
1535
1536
1522
1523
1524
1525
1526
1527
1528

1529
1530
1531
1532
1533
1534
1535
1536







-
+







}

/*
 *----------------------------------------------------------------------
 *
 * HandleIMEComposition --
 *
 *	This function works around a definciency in some versions of Windows
 *	This function works around a deficiency in some versions of Windows
 *	2000 to make it possible to entry multi-lingual characters under all
 *	versions of Windows 2000.
 *
 *	When an Input Method Editor (IME) is ready to send input characters to
 *	an application, it sends a WM_IME_COMPOSITION message with the
 *	GCS_RESULTSTR. However, The DefWindowProc() on English Windows 2000
 *	arbitrarily converts all non-Latin-1 characters in the composition to
1552
1553
1554
1555
1556
1557
1558

1559
1560
1561
1562
1563
1564
1565
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566







+







static int
HandleIMEComposition(
    HWND hwnd,			/* Window receiving the message. */
    LPARAM lParam)		/* Flags for the WM_IME_COMPOSITION message */
{
    HIMC hIMC;
    int n;
    int high = 0;

    if ((lParam & GCS_RESULTSTR) == 0) {
	/*
	 * Composition is not finished yet.
	 */

	return 0;
1608
1609
1610
1611
1612
1613
1614








1615
1616
1617
1618
1619
1620
1621
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630







+
+
+
+
+
+
+
+







	    /*
	     * Simulate a pair of KeyPress and KeyRelease events for each
	     * UNICODE character in the composition.
	     */

	    event.xkey.keycode = buff[i++];

	    if ((event.xkey.keycode & 0xfc00) == 0xd800) {
		high = ((event.xkey.keycode & 0x3ff) << 10) + 0x10000;
		break;
	    } else if (high && (event.xkey.keycode & 0xfc00) == 0xdc00) {
		event.xkey.keycode &= 0x3ff;
		event.xkey.keycode += high;
		high = 0;
	    }
	    event.type = KeyPress;
	    Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);

	    event.type = KeyRelease;
	    Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
	}