summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvincentdarley <vincentdarley>2003-12-04 12:09:55 (GMT)
committervincentdarley <vincentdarley>2003-12-04 12:09:55 (GMT)
commit50c35588c1284033589929bdf168163d5f9f7a8d (patch)
tree9cff7de3afeb0dd3ffe36e6e86f94c00e27ad5e7
parent5d9923f32aa62c0eb4d627f5c4b6898f61308a7b (diff)
downloadtk-50c35588c1284033589929bdf168163d5f9f7a8d.zip
tk-50c35588c1284033589929bdf168163d5f9f7a8d.tar.gz
tk-50c35588c1284033589929bdf168163d5f9f7a8d.tar.bz2
font measurement fix
-rw-r--r--ChangeLog7
-rw-r--r--tests/textDisp.test25
-rw-r--r--win/tkWinFont.c251
3 files changed, 161 insertions, 122 deletions
diff --git a/ChangeLog b/ChangeLog
index 0bcd3da..121adac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2003-12-04 Vince Darley <vincentdarley@users.sourceforge.net>
+
+ * win/tkWinFont.c: applied [Patch 852669] which fixes [Bug 478568]
+ with certain bold or italic fonts on Windows.
+ * tests/textDisp.test: added test for the font measurement
+ problem.
+
2003-12-02 Jeff Hobbs <jeffh@ActiveState.com>
* generic/tkMenu.c (MenuVarProc): prevent this from triggering
diff --git a/tests/textDisp.test b/tests/textDisp.test
index 31abdd1..7f1a54a 100644
--- a/tests/textDisp.test
+++ b/tests/textDisp.test
@@ -6,7 +6,7 @@
# Copyright (c) 1998-1999 by Scriptics Corporation.
# All rights reserved.
#
-# RCS: @(#) $Id: textDisp.test,v 1.22 2003/11/21 18:51:18 vincentdarley Exp $
+# RCS: @(#) $Id: textDisp.test,v 1.23 2003/12/04 12:10:07 vincentdarley Exp $
package require tcltest 2.1
eval tcltest::configure $argv
@@ -3579,6 +3579,29 @@ test textDisp-33.4 {one line longer than fits in the widget} {
set result
} {ok}
destroy .tt
+test textDisp-33.5 {bold or italic fonts} {winOnly} {
+ destroy .tt
+ pack [text .tt -wrap char -font {{MS Sans Serif} 15}]
+ font create no -family [lindex [.tt cget -font] 0] -size 24
+ font create bi -family [lindex [.tt cget -font] 0] -size 24
+ font configure bi -weight bold -slant italic
+ .tt tag configure bi -font bi
+ .tt tag configure no -font no
+ .tt insert end abcd no efgh bi ijkl\n no
+ update
+ set bb {}
+ for {set i 0} {$i < 12} {incr i 4} {
+ lappend bb [lindex [.tt bbox 1.$i] 0]
+ }
+ foreach {a b c} $bb {}
+ unset bb
+ if {($b - $a) * 1.5 < ($c - $b)} {
+ set result "italic font has much too much space"
+ } else {
+ set result "italic font measurement ok"
+ }
+} {italic font measurement ok}
+destroy .tt
deleteWindows
option clear
diff --git a/win/tkWinFont.c b/win/tkWinFont.c
index acdd28f..61633d6 100644
--- a/win/tkWinFont.c
+++ b/win/tkWinFont.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkWinFont.c,v 1.17 2003/02/26 02:47:05 hobbs Exp $
+ * RCS: @(#) $Id: tkWinFont.c,v 1.18 2003/12/04 12:09:55 vincentdarley Exp $
*/
#include "tkWinInt.h"
@@ -602,16 +602,21 @@ Tk_MeasureChars(
HDC hdc;
HFONT oldFont;
WinFont *fontPtr;
- int curX, curByte;
+ int curX;
+ Tcl_UniChar ch;
+ SIZE size;
+ int moretomeasure;
+ FontFamily *familyPtr;
+ Tcl_DString runString;
+ SubFont *thisSubFontPtr;
SubFont *lastSubFontPtr;
+ CONST char *p, *end, *next, *start;
- /*
- * According to Microsoft tech support, Windows does not use kerning
- * or fractional character widths when displaying text on the screen.
- * So that means we can safely measure individual characters or spans
- * of characters and add up the widths w/o any "off-by-one-pixel"
- * errors.
- */
+
+ if (numBytes == 0) {
+ *lengthPtr = 0;
+ return 0;
+ }
fontPtr = (WinFont *) tkfont;
@@ -619,17 +624,6 @@ Tk_MeasureChars(
lastSubFontPtr = &fontPtr->subFontArray[0];
oldFont = SelectObject(hdc, lastSubFontPtr->hFont);
- if (numBytes == 0) {
- curX = 0;
- curByte = 0;
- } else if (maxLength < 0) {
- Tcl_UniChar ch;
- SIZE size;
- FontFamily *familyPtr;
- Tcl_DString runString;
- SubFont *thisSubFontPtr;
- CONST char *p, *end, *next;
-
/*
* A three step process:
* 1. Find a contiguous range of characters that can all be
@@ -638,142 +632,153 @@ Tk_MeasureChars(
* 3. Measure converted chars.
*/
- curX = 0;
- end = source + numBytes;
- for (p = source; p < end; ) {
+ moretomeasure = 0;
+ curX = 0;
+ start = source;
+ end = start + numBytes;
+ for (p = start; p < end; ) {
next = p + Tcl_UtfToUniChar(p, &ch);
thisSubFontPtr = FindSubFontForChar(fontPtr, ch);
if (thisSubFontPtr != lastSubFontPtr) {
familyPtr = lastSubFontPtr->familyPtr;
- Tcl_UtfToExternalDString(familyPtr->encoding, source,
- (int) (p - source), &runString);
+ Tcl_UtfToExternalDString(familyPtr->encoding, start,
+ (int) (p - start), &runString);
(*familyPtr->getTextExtentPoint32Proc)(hdc,
Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
&size);
- curX += size.cx;
- Tcl_DStringFree(&runString);
- lastSubFontPtr = thisSubFontPtr;
- source = p;
-
- SelectObject(hdc, lastSubFontPtr->hFont);
+ if (maxLength >= 0 && (curX+size.cx) > maxLength) {
+ moretomeasure = 1;
+ break;
}
- p = next;
- }
+ curX += size.cx;
+ Tcl_DStringFree(&runString);
+ lastSubFontPtr = thisSubFontPtr;
+ start = p;
+
+ SelectObject(hdc, lastSubFontPtr->hFont);
+ }
+ p = next;
+ }
+
+ if (!moretomeasure) {
+ /*
+ * We get here if the previous loop was just finished
+ * normally, without a break. Just measure the last run and
+ * that's it.
+ */
+
familyPtr = lastSubFontPtr->familyPtr;
- Tcl_UtfToExternalDString(familyPtr->encoding, source,
- (int) (p - source), &runString);
+ Tcl_UtfToExternalDString(familyPtr->encoding, start,
+ (int) (p - start), &runString);
(*familyPtr->getTextExtentPoint32Proc)(hdc,
Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
&size);
- curX += size.cx;
- Tcl_DStringFree(&runString);
- curByte = numBytes;
- } else {
- Tcl_UniChar ch;
- SIZE size;
- char buf[16];
- FontFamily *familyPtr;
- SubFont *thisSubFontPtr;
- CONST char *term, *end, *p, *next;
- int newX, termX, sawNonSpace, dstWrote;
+ if (maxLength >= 0 && (curX+size.cx) > maxLength) {
+ moretomeasure = 1;
+ } else {
+ curX += size.cx;
+ Tcl_DStringFree(&runString);
+ p = end;
+ }
+ }
+ if (moretomeasure) {
/*
- * How many chars will fit in the space allotted?
- * This first version may be inefficient because it measures
- * every character individually. There is a function call that
- * can measure multiple characters at once and return the
- * offset of each of them, but it only works on NT, even though
- * the documentation claims it works for 95.
- * TODO: verify that GetTextExtentExPoint is still broken in '95, and
- * possibly use it for NT anyway since it should be much faster and
- * more accurate.
+ * We get here if the measurement of the last run was over the
+ * maxLength limit. We need to restart this run and do it
+ * char by char, but always in context with the previous text
+ * to account for kerning (especially italics).
*/
- next = source + Tcl_UtfToUniChar(source, &ch);
- newX = curX = termX = 0;
-
- term = source;
- end = source + numBytes;
-
- sawNonSpace = (ch > 255) || !isspace(ch);
- for (p = source; ; ) {
- if (ch < BASE_CHARS) {
- newX += fontPtr->widths[ch];
- } else {
- thisSubFontPtr = FindSubFontForChar(fontPtr, ch);
- if (thisSubFontPtr != lastSubFontPtr) {
- SelectObject(hdc, thisSubFontPtr->hFont);
- lastSubFontPtr = thisSubFontPtr;
- }
- familyPtr = lastSubFontPtr->familyPtr;
+ char buf[16];
+ int dstWrote;
+ int lastSize;
+
+ familyPtr = lastSubFontPtr->familyPtr;
+ Tcl_DStringInit(&runString);
+ for (p = start; p < end; ) {
+ next = p + Tcl_UtfToUniChar(p, &ch);
Tcl_UtfToExternal(NULL, familyPtr->encoding, p,
(int) (next - p), 0, NULL, buf, sizeof(buf), NULL,
&dstWrote, NULL);
- (*familyPtr->getTextExtentPoint32Proc)(hdc, buf,
- dstWrote >> familyPtr->isWideFont, &size);
- newX += size.cx;
- }
- if (newX > maxLength) {
+ Tcl_DStringAppend(&runString,buf,dstWrote);
+ (*familyPtr->getTextExtentPoint32Proc)(hdc,
+ Tcl_DStringValue(&runString),
+ Tcl_DStringLength(&runString) >> familyPtr->isWideFont,
+ &size);
+ if ((curX+size.cx) > maxLength) {
break;
}
- curX = newX;
+ lastSize = size.cx;
p = next;
- if (p >= end) {
- term = end;
- termX = curX;
- break;
- }
+ }
+ Tcl_DStringFree(&runString);
- next += Tcl_UtfToUniChar(next, &ch);
- if ((ch < 256) && isspace(ch)) {
- if (sawNonSpace) {
- term = p;
- termX = curX;
- sawNonSpace = 0;
- }
- } else {
- sawNonSpace = 1;
- }
+ /*
+ * "p" points to the first character that doesn't fit in the
+ * desired span. Look at the flags to figure out whether to
+ * include this next character.
+ */
+
+ if ((p < end)
+ && (((flags & TK_PARTIAL_OK) && curX != maxLength)
+ || ((flags & TK_AT_LEAST_ONE) && (curX == 0)))) {
+
+ /*
+ * Include the first character that didn't quite fit in
+ * the desired span. The width returned will include the
+ * width of that extra character.
+ */
+
+ p = next;
+ curX += size.cx;
+ } else {
+ curX += lastSize;
}
+ }
+
+ SelectObject(hdc, oldFont);
+ ReleaseDC(fontPtr->hwnd, hdc);
+
+ if ((flags & TK_WHOLE_WORDS) && (p < end)
+ && !((ch < 128) && isspace(ch))) {
/*
- * P points to the first character that doesn't fit in the desired
- * span. Use the flags to figure out what to return.
+ * This is never used by Tk itself, but others may want it.
+ * Scan the string for the last word break and repeat the
+ * whole procedure without the maxLength limit or any flags.
*/
- if ((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) {
- /*
- * Include the first character that didn't quite fit in the desired
- * span. The width returned will include the width of that extra
- * character.
- */
+ CONST char *lastWordBreak = NULL;
+ CONST char *nextafter = NULL;
+ Tcl_UniChar ch2;
- curX = newX;
- p += Tcl_UtfToUniChar(p, &ch);
- }
- if ((flags & TK_AT_LEAST_ONE) && (term == source) && (p < end)) {
- term = p;
- termX = curX;
- if (term == source) {
- term += Tcl_UtfToUniChar(term, &ch);
- termX = newX;
+ end = p;
+ start = source;
+
+ next = p + Tcl_UtfToUniChar(p, &ch);
+ for (p = start; next < end; ) {
+ nextafter = next + Tcl_UtfToUniChar(next, &ch2);
+ if (((ch >= 128) || !isspace(ch))
+ && ((ch2 < 128) && isspace(ch2))) {
+ lastWordBreak = next;
}
- } else if ((p >= end) || !(flags & TK_WHOLE_WORDS)) {
- term = p;
- termX = curX;
+ p = next;
+ next = nextafter;
}
- curX = termX;
- curByte = (int) (term - source);
+ if (NULL != lastWordBreak) {
+ return Tk_MeasureChars(
+ tkfont, source, lastWordBreak-source, -1, 0, lengthPtr );
+ } else {
+ p = end;
+ }
}
- SelectObject(hdc, oldFont);
- ReleaseDC(fontPtr->hwnd, hdc);
-
*lengthPtr = curX;
- return curByte;
+ return p - source;
}
/*
@@ -976,9 +981,11 @@ MultiFontTextOut(
Tcl_DString runString;
CONST char *p, *end, *next;
SubFont *lastSubFontPtr, *thisSubFontPtr;
+ TEXTMETRIC tm;
lastSubFontPtr = &fontPtr->subFontArray[0];
oldFont = SelectObject(hdc, lastSubFontPtr->hFont);
+ GetTextMetrics(hdc, &tm);
end = source + numBytes;
for (p = source; p < end; ) {
@@ -989,7 +996,7 @@ MultiFontTextOut(
familyPtr = lastSubFontPtr->familyPtr;
Tcl_UtfToExternalDString(familyPtr->encoding, source,
(int) (p - source), &runString);
- (*familyPtr->textOutProc)(hdc, x, y,
+ (*familyPtr->textOutProc)(hdc, x-(tm.tmOverhang/2), y,
Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString) >> familyPtr->isWideFont);
(*familyPtr->getTextExtentPoint32Proc)(hdc,
@@ -1002,6 +1009,7 @@ MultiFontTextOut(
lastSubFontPtr = thisSubFontPtr;
source = p;
SelectObject(hdc, lastSubFontPtr->hFont);
+ GetTextMetrics(hdc, &tm);
}
p = next;
}
@@ -1009,7 +1017,8 @@ MultiFontTextOut(
familyPtr = lastSubFontPtr->familyPtr;
Tcl_UtfToExternalDString(familyPtr->encoding, source,
(int) (p - source), &runString);
- (*familyPtr->textOutProc)(hdc, x, y, Tcl_DStringValue(&runString),
+ (*familyPtr->textOutProc)(hdc, x-(tm.tmOverhang/2), y,
+ Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString) >> familyPtr->isWideFont);
Tcl_DStringFree(&runString);
}