#include "tkUnixInt.h"
#include "tkFont.h"
#ifndef USE_XFT_FONTS
#include <netinet/in.h> /* for htons() prototype */
#include <arpa/inet.h> /* inet_ntoa() */
static
CONST
char
*encodingList[] = {
"iso8859-1"
,
"jis0208"
,
"jis0212"
,
"ksc5601"
,
"big5"
,
"ucs-2be"
, NULL
};
#if TCL_UTF_MAX <= 3
#define FONTMAP_SHIFT 8
#else
#define FONTMAP_SHIFT 10
#endif
#define FONTMAP_PAGES (1 << (sizeof(Tcl_UniChar)*8 - FONTMAP_SHIFT))
#define FONTMAP_BITSPERPAGE (1 << FONTMAP_SHIFT)
typedef
struct
FontFamily {
struct
FontFamily *nextPtr;
int
refCount;
Tk_Uid foundry;
Tk_Uid faceName;
Tcl_Encoding encoding;
int
isTwoByteFont;
char
*fontMap[FONTMAP_PAGES];
} FontFamily;
typedef
struct
SubFont {
char
**fontMap;
XFontStruct *fontStructPtr;
FontFamily *familyPtr;
char
*name;
int
trigger;
} SubFont;
#define SUBFONT_SPACE 3
#define BASE_CHARS 256
typedef
struct
UnixFont {
TkFont font;
SubFont staticSubFonts[SUBFONT_SPACE];
int
numSubFonts;
SubFont *subFontArray;
SubFont controlSubFont;
Display *display;
int
pixelSize;
TkXLFDAttributes xa;
int
widths[BASE_CHARS];
int
underlinePos;
int
barHeight;
} UnixFont;
typedef
struct
EncodingAlias {
char
*realName;
char
*aliasPattern;
} EncodingAlias;
typedef
struct
FontAttributes {
TkFontAttributes fa;
TkXLFDAttributes xa;
} FontAttributes;
typedef
struct
ThreadSpecificData {
FontFamily *fontFamilyList;
FontFamily controlFamily;
} ThreadSpecificData;
static
Tcl_ThreadDataKey dataKey;
static
EncodingAlias encodingAliases[] = {
{
"gb2312-raw"
,
"gb2312*"
},
{
"big5"
,
"big5*"
},
{
"cns11643-1"
,
"cns11643*-1"
},
{
"cns11643-1"
,
"cns11643*.1-0"
},
{
"cns11643-2"
,
"cns11643*-2"
},
{
"cns11643-2"
,
"cns11643*.2-0"
},
{
"jis0201"
,
"jisx0201*"
},
{
"jis0201"
,
"jisx0202*"
},
{
"jis0208"
,
"jisc6226*"
},
{
"jis0208"
,
"jisx0208*"
},
{
"jis0212"
,
"jisx0212*"
},
{
"tis620"
,
"tis620*"
},
{
"ksc5601"
,
"ksc5601*"
},
{
"dingbats"
,
"*dingbats"
},
{
"ucs-2be"
,
"iso10646-1"
},
{NULL, NULL}
};
static
void
FontPkgCleanup _ANSI_ARGS_((ClientData clientData));
static
FontFamily * AllocFontFamily _ANSI_ARGS_((Display *display,
XFontStruct *fontStructPtr,
int
base));
static
SubFont * CanUseFallback _ANSI_ARGS_((UnixFont *fontPtr,
CONST
char
*fallbackName,
int
ch,
SubFont **fixSubFontPtrPtr));
static
SubFont * CanUseFallbackWithAliases _ANSI_ARGS_((
UnixFont *fontPtr,
char
*fallbackName,
int
ch, Tcl_DString *nameTriedPtr,
SubFont **fixSubFontPtrPtr));
static
int
ControlUtfProc _ANSI_ARGS_((ClientData clientData,
CONST
char
*src,
int
srcLen,
int
flags,
Tcl_EncodingState *statePtr,
char
*dst,
int
dstLen,
int
*srcReadPtr,
int
*dstWrotePtr,
int
*dstCharsPtr));
static
XFontStruct * CreateClosestFont _ANSI_ARGS_((Tk_Window tkwin,
CONST TkFontAttributes *faPtr,
CONST TkXLFDAttributes *xaPtr));
static
SubFont * FindSubFontForChar _ANSI_ARGS_((UnixFont *fontPtr,
int
ch, SubFont **fixSubFontPtrPtr));
static
void
FontMapInsert _ANSI_ARGS_((SubFont *subFontPtr,
int
ch));
static
void
FontMapLoadPage _ANSI_ARGS_((SubFont *subFontPtr,
int
row));
static
int
FontMapLookup _ANSI_ARGS_((SubFont *subFontPtr,
int
ch));
static
void
FreeFontFamily _ANSI_ARGS_((FontFamily *afPtr));
static
CONST
char
* GetEncodingAlias _ANSI_ARGS_((CONST
char
*name));
static
int
GetFontAttributes _ANSI_ARGS_((Display *display,
XFontStruct *fontStructPtr, FontAttributes *faPtr));
static
XFontStruct * GetScreenFont _ANSI_ARGS_((Display *display,
FontAttributes *wantPtr,
char
**nameList,
int
bestIdx[], unsigned
int
bestScore[],
int
*indexPtr));
static
XFontStruct * GetSystemFont _ANSI_ARGS_((Display *display));
static
int
IdentifySymbolEncodings _ANSI_ARGS_((
FontAttributes *faPtr));
static
void
InitFont _ANSI_ARGS_((Tk_Window tkwin,
XFontStruct *fontStructPtr, UnixFont *fontPtr));
static
void
InitSubFont _ANSI_ARGS_((Display *display,
XFontStruct *fontStructPtr,
int
base,
SubFont *subFontPtr));
static
char
** ListFonts _ANSI_ARGS_((Display *display,
CONST
char
*faceName,
int
*numNamesPtr));
static
char
** ListFontOrAlias _ANSI_ARGS_((Display *display,
CONST
char
*faceName,
int
*numNamesPtr));
static
unsigned
int
RankAttributes _ANSI_ARGS_((FontAttributes *wantPtr,
FontAttributes *gotPtr,
int
ch,
const
char
*name));
static
void
ReleaseFont _ANSI_ARGS_((UnixFont *fontPtr));
static
void
ReleaseSubFont _ANSI_ARGS_((Display *display,
SubFont *subFontPtr));
static
int
SeenName _ANSI_ARGS_((CONST
char
*name,
Tcl_DString *dsPtr));
static
int
Ucs2beToUtfProc _ANSI_ARGS_((ClientData clientData,
CONST
char
*src,
int
srcLen,
int
flags,
Tcl_EncodingState *statePtr,
char
*dst,
int
dstLen,
int
*srcReadPtr,
int
*dstWrotePtr,
int
*dstCharsPtr));
static
int
UtfToUcs2beProc _ANSI_ARGS_((ClientData clientData,
CONST
char
*src,
int
srcLen,
int
flags,
Tcl_EncodingState *statePtr,
char
*dst,
int
dstLen,
int
*srcReadPtr,
int
*dstWrotePtr,
int
*dstCharsPtr));
static
void
FontPkgCleanup(ClientData clientData)
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey,
sizeof
(ThreadSpecificData));
if
(tsdPtr->controlFamily.encoding != NULL) {
FontFamily *familyPtr = &tsdPtr->controlFamily;
int
i;
Tcl_FreeEncoding(familyPtr->encoding);
for
(i = 0; i < FONTMAP_PAGES; i++) {
if
(familyPtr->fontMap[i] != NULL) {
ckfree(familyPtr->fontMap[i]);
}
}
tsdPtr->controlFamily.encoding = NULL;
}
}
void
TkpFontPkgInit(mainPtr)
TkMainInfo *mainPtr;
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey,
sizeof
(ThreadSpecificData));
SubFont dummy;
int
i;
if
(tsdPtr->controlFamily.encoding == NULL) {
tsdPtr->controlFamily.refCount = 2;
tsdPtr->controlFamily.encoding = Lang_CreateEncoding(
"X11ControlChars"
,
ControlUtfProc,
ControlUtfProc,
NULL,
NULL,
0
);
tsdPtr->controlFamily.isTwoByteFont = 0;
dummy.familyPtr = &tsdPtr->controlFamily;
dummy.fontMap = tsdPtr->controlFamily.fontMap;
for
(i = 0x00; i < 0x20; i++) {
FontMapInsert(&dummy, i);
FontMapInsert(&dummy, i + 0x80);
}
#ifndef _LANG
type.encodingName =
"ucs-2be"
;
type.toUtfProc = Ucs2beToUtfProc;
type.fromUtfProc = UtfToUcs2beProc;
type.freeProc = NULL;
type.clientData = NULL;
type.nullSize = 2;
Tcl_CreateEncoding(&type);
Tcl_CreateThreadExitHandler(FontPkgCleanup, NULL);
#else
Lang_CreateEncoding(
"ucs-2be"
,
Ucs2beToUtfProc,
UtfToUcs2beProc,
NULL,
NULL,
2);
#endif
}
}
static
int
ControlUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen,
srcReadPtr, dstWrotePtr, dstCharsPtr)
ClientData clientData;
CONST
char
*src;
int
srcLen;
int
flags;
Tcl_EncodingState *statePtr;
char
*dst;
int
dstLen;
int
*srcReadPtr;
int
*dstWrotePtr;
int
*dstCharsPtr;
{
CONST
char
*srcStart, *srcEnd;
char
*dstStart, *dstEnd;
Tcl_UniChar 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);
dst[0] =
'\\'
;
if
((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
{
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;
}
}
*srcReadPtr = src - srcStart;
*dstWrotePtr = dst - dstStart;
*dstCharsPtr = dst - dstStart;
return
result;
}
static
int
Ucs2beToUtfProc(clientData, src, srcLen, flags, statePtr, dst, dstLen,
srcReadPtr, dstWrotePtr, dstCharsPtr)
ClientData clientData;
CONST
char
*src;
int
srcLen;
int
flags;
Tcl_EncodingState *statePtr;
char
*dst;
int
dstLen;
int
*srcReadPtr;
int
*dstWrotePtr;
int
*dstCharsPtr;
{
CONST Tcl_UniChar *wSrc, *wSrcStart, *wSrcEnd;
char
*dstEnd, *dstStart;
int
result, numChars;
result = TCL_OK;
if
((srcLen %
sizeof
(Tcl_UniChar)) != 0) {
result = TCL_CONVERT_MULTIBYTE;
srcLen /=
sizeof
(Tcl_UniChar);
srcLen *=
sizeof
(Tcl_UniChar);
}
wSrc = (Tcl_UniChar *) src;
wSrcStart = (Tcl_UniChar *) src;
wSrcEnd = (Tcl_UniChar *) (src + srcLen);
dstStart = dst;
dstEnd = dst + dstLen - TCL_UTF_MAX;
for
(numChars = 0; wSrc < wSrcEnd; numChars++) {
if
(dst > dstEnd) {
result = TCL_CONVERT_NOSPACE;
break
;
}
dst += Tcl_UniCharToUtf(htons(*wSrc), dst);
wSrc++;
}
*srcReadPtr = (
char
*) wSrc - (
char
*) wSrcStart;
*dstWrotePtr = dst - dstStart;
*dstCharsPtr = numChars;
return
result;
}
static
int
UtfToUcs2beProc(clientData, src, srcLen, flags, statePtr, dst, dstLen,
srcReadPtr, dstWrotePtr, dstCharsPtr)
ClientData clientData;
CONST
char
*src;
int
srcLen;
int
flags;
Tcl_EncodingState *statePtr;
char
*dst;
int
dstLen;
int
*srcReadPtr;
int
*dstWrotePtr;
int
*dstCharsPtr;
{
CONST
char
*srcStart, *srcEnd, *srcClose;
Tcl_UniChar *wDst, *wDstStart, *wDstEnd;
int
result, numChars;
srcStart = src;
srcEnd = src + srcLen;
srcClose = srcEnd;
if
((flags & TCL_ENCODING_END) == 0) {
srcClose -= TCL_UTF_MAX;
}
wDst = (Tcl_UniChar *) dst;
wDstStart = (Tcl_UniChar *) dst;
wDstEnd = (Tcl_UniChar *) (dst + dstLen -
sizeof
(Tcl_UniChar));
result = TCL_OK;
for
(numChars = 0; src < srcEnd; numChars++) {
if
((src > srcClose) && (!Tcl_UtfCharComplete(src, srcEnd - src))) {
result = TCL_CONVERT_MULTIBYTE;
break
;
}
if
(wDst > wDstEnd) {
result = TCL_CONVERT_NOSPACE;
break
;
}
src += Tcl_UtfToUniChar(src, wDst);
*wDst = htons(*wDst);
wDst++;
}
*srcReadPtr = src - srcStart;
*dstWrotePtr = (
char
*) wDst - (
char
*) wDstStart;
*dstCharsPtr = numChars;
return
result;
}
TkFont *
TkpGetNativeFont(tkwin, name)
Tk_Window tkwin;
CONST
char
*name;
{
UnixFont *fontPtr;
XFontStruct *fontStructPtr;
FontAttributes fa;
CONST
char
*p;
int
hasSpace, dashes, hasWild;
hasSpace = dashes = hasWild = 0;
for
(p = name; *p !=
'\0'
; p++) {
if
(*p ==
' '
) {
if
(p[1] ==
'-'
) {
return
NULL;
}
hasSpace = 1;
}
else
if
(*p ==
'-'
) {
dashes++;
}
else
if
(*p ==
'*'
) {
hasWild = 1;
}
}
if
((dashes < 14) && !hasWild && hasSpace) {
return
NULL;
}
fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), name);
if
(fontStructPtr == NULL) {
if
(name[0] ==
'-'
) {
if
(name[1] !=
'*'
) {
char
*dash;
dash =
strchr
(name + 1,
'-'
);
if
((dash == NULL) || (
isspace
(
UCHAR
(dash[-1])))) {
return
NULL;
}
}
}
else
if
(name[0] !=
'*'
) {
return
NULL;
}
if
(TkFontParseXLFD(name, &fa.fa, &fa.xa) != TCL_OK) {
return
NULL;
}
fontStructPtr = CreateClosestFont(tkwin, &fa.fa, &fa.xa);
}
fontPtr = (UnixFont *) ckalloc(
sizeof
(UnixFont));
InitFont(tkwin, fontStructPtr, fontPtr);
return
(TkFont *) fontPtr;
}
TkFont *
TkpGetFontFromAttributes(tkFontPtr, tkwin, faPtr)
TkFont *tkFontPtr;
Tk_Window tkwin;
CONST TkFontAttributes *faPtr;
{
UnixFont *fontPtr;
TkXLFDAttributes xa;
XFontStruct *fontStructPtr;
TkInitXLFDAttributes(&xa);
fontStructPtr = CreateClosestFont(tkwin, faPtr, &xa);
fontPtr = (UnixFont *) tkFontPtr;
if
(fontPtr == NULL) {
fontPtr = (UnixFont *) ckalloc(
sizeof
(UnixFont));
}
else
{
ReleaseFont(fontPtr);
}
InitFont(tkwin, fontStructPtr, fontPtr);
fontPtr->font.fa.underline = faPtr->underline;
fontPtr->font.fa.overstrike = faPtr->overstrike;
return
(TkFont *) fontPtr;
}
void
TkpDeleteFont(tkFontPtr)
TkFont *tkFontPtr;
{
UnixFont *fontPtr;
fontPtr = (UnixFont *) tkFontPtr;
ReleaseFont(fontPtr);
}
void
TkpGetFontFamilies(interp, tkwin)
Tcl_Interp *interp;
Tk_Window tkwin;
{
int
i,
new
, numNames;
char
*family;
Tcl_HashTable familyTable;
Tcl_HashEntry *hPtr;
Tcl_HashSearch search;
char
**nameList;
Tcl_Obj *resultPtr, *strPtr;
resultPtr = Tcl_GetObjResult(interp);
Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS);
nameList = ListFonts(Tk_Display(tkwin),
"*"
, &numNames);
for
(i = 0; i < numNames; i++) {
family =
strchr
(nameList[i] + 1,
'-'
) + 1;
strchr
(family,
'-'
)[0] =
'\0'
;
Tcl_CreateHashEntry(&familyTable, family, &
new
);
}
XFreeFontNames(nameList);
hPtr = Tcl_FirstHashEntry(&familyTable, &search);
while
(hPtr != NULL) {
strPtr = Tcl_NewStringObj(Tcl_GetHashKey(&familyTable, hPtr), -1);
Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
hPtr = Tcl_NextHashEntry(&search);
}
Tcl_DeleteHashTable(&familyTable);
}
void
TkpGetSubFonts(interp, tkfont)
Tcl_Interp *interp;
Tk_Font tkfont;
{
int
i;
Tcl_Obj *objv[4];
Tcl_Obj *resultPtr, *listPtr;
UnixFont *fontPtr;
FontFamily *familyPtr;
resultPtr = Tcl_GetObjResult(interp);
fontPtr = (UnixFont *) tkfont;
for
(i = 0; i < fontPtr->numSubFonts; i++) {
familyPtr = fontPtr->subFontArray[i].familyPtr;
objv[0] = Tcl_NewStringObj(familyPtr->faceName, -1);
objv[1] = Tcl_NewStringObj(familyPtr->foundry, -1);
objv[2] = Tcl_NewStringObj(Tcl_GetEncodingName(familyPtr->encoding), -1);
objv[3] = Tcl_NewIntObj(fontPtr->subFontArray[i].trigger);
listPtr = Tcl_NewListObj(4, objv);
if
(fontPtr->subFontArray[i].name) {
Tcl_ListObjAppendElement(interp, listPtr,
Tcl_NewStringObj(fontPtr->subFontArray[i].name, -1));
}
Tcl_ListObjAppendElement(interp, resultPtr, listPtr);
}
}
int
Tk_MeasureChars(tkfont, source, numBytes, maxLength, flags, lengthPtr)
Tk_Font tkfont;
CONST
char
*source;
int
numBytes;
int
maxLength;
int
flags;
int
*lengthPtr;
{
UnixFont *fontPtr;
SubFont *lastSubFontPtr;
int
curX, curByte;
fontPtr = (UnixFont *) tkfont;
lastSubFontPtr = &fontPtr->subFontArray[0];
if
(numBytes == 0) {
curX = 0;
curByte = 0;
}
else
if
(maxLength < 0) {
CONST
char
*p, *end, *next;
Tcl_UniChar ch;
SubFont *thisSubFontPtr;
FontFamily *familyPtr;
Tcl_DString runString;
curX = 0;
end = source + numBytes;
for
(p = source; p < end; ) {
next = p + Tcl_UtfToUniChar(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,
(XChar2b *) Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString) / 2);
}
else
{
curX += XTextWidth(lastSubFontPtr->fontStructPtr,
Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString));
}
Tcl_DStringFree(&runString);
lastSubFontPtr = thisSubFontPtr;
source = p;
}
p = next;
}
familyPtr = lastSubFontPtr->familyPtr;
Tcl_UtfToExternalDString(familyPtr->encoding, source, p - source,
&runString);
if
(familyPtr->isTwoByteFont) {
curX += XTextWidth16(lastSubFontPtr->fontStructPtr,
(XChar2b *) Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString) >> 1);
}
else
{
curX += XTextWidth(lastSubFontPtr->fontStructPtr,
Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString));
}
Tcl_DStringFree(&runString);
curByte = numBytes;
}
else
{
CONST
char
*p, *end, *next, *term;
int
newX, termX, sawNonSpace, dstWrote;
Tcl_UniChar ch;
FontFamily *familyPtr;
char
buf[16];
next = source + Tcl_UtfToUniChar(source, &ch);
newX = curX = termX = 0;
term = source;
end = source + numBytes;
sawNonSpace = (ch > 255) || !
isspace
(ch);
familyPtr = lastSubFontPtr->familyPtr;
for
(p = source; ; ) {
if
((ch < BASE_CHARS) && (fontPtr->widths[ch] != 0)) {
newX += fontPtr->widths[ch];
}
else
{
lastSubFontPtr = FindSubFontForChar(fontPtr, ch, NULL);
familyPtr = lastSubFontPtr->familyPtr;
Tcl_UtfToExternal(NULL, familyPtr->encoding, p, next - p,
0, NULL, buf,
sizeof
(buf), NULL, &dstWrote, NULL);
if
(familyPtr->isTwoByteFont) {
newX += XTextWidth16(lastSubFontPtr->fontStructPtr,
(XChar2b *) buf, dstWrote >> 1);
}
else
{
newX += XTextWidth(lastSubFontPtr->fontStructPtr, buf,
dstWrote);
}
}
if
(newX > maxLength) {
break
;
}
curX = newX;
p = next;
if
(p >= end) {
term = end;
termX = curX;
break
;
}
next += Tcl_UtfToUniChar(next, &ch);
if
((ch < 256) &&
isspace
(ch)) {
if
(sawNonSpace) {
term = p;
termX = curX;
sawNonSpace = 0;
}
}
else
{
sawNonSpace = 1;
}
}
if
((flags & TK_PARTIAL_OK) && (p < end) && (curX < maxLength)) {
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;
}
}
else
if
((p >= end) || !(flags & TK_WHOLE_WORDS)) {
term = p;
termX = curX;
}
curX = termX;
curByte = term - source;
}
*lengthPtr = curX;
return
curByte;
}
void
Tk_DrawChars(display, drawable, gc, tkfont, source, numBytes, x, y)
Display *display;
Drawable drawable;
GC gc;
Tk_Font tkfont;
CONST
char
*source;
int
numBytes;
int
x, y;
{
UnixFont *fontPtr;
SubFont *thisSubFontPtr, *lastSubFontPtr;
Tcl_DString runString;
CONST
char
*p, *end, *next;
int
xStart, needWidth, window_width, do_width;
Tcl_UniChar ch;
FontFamily *familyPtr;
#ifdef TK_DRAW_CHAR_XWINDOW_CHECK
int
rx, ry;
unsigned
int
width, height, border_width, depth;
Drawable root;
#endif
fontPtr = (UnixFont *) tkfont;
lastSubFontPtr = &fontPtr->subFontArray[0];
xStart = x;
#ifdef TK_DRAW_CHAR_XWINDOW_CHECK
if
(XGetGeometry(display, drawable, &root, &rx, &ry, &width, &height,
&border_width, &depth) == False) {
window_width = INT_MAX;
}
else
{
window_width = width;
}
#else
window_width = 32768;
#endif
end = source + numBytes;
needWidth = fontPtr->font.fa.underline + fontPtr->font.fa.overstrike;
for
(p = source; p <= end; ) {
if
(p < end) {
next = p + Tcl_UtfToUniChar(p, &ch);
thisSubFontPtr = FindSubFontForChar(fontPtr, ch, &lastSubFontPtr);
}
else
{
next = p + 1;
thisSubFontPtr = lastSubFontPtr;
}
if
((thisSubFontPtr != lastSubFontPtr)
|| (p == end) || (p-source > 200)) {
if
(p > source) {
do_width = (needWidth || (p != end)) ? 1 : 0;
familyPtr = lastSubFontPtr->familyPtr;
Tcl_UtfToExternalDString(familyPtr->encoding, source,
p - source, &runString);
if
(familyPtr->isTwoByteFont) {
XDrawString16(display, drawable, gc, x, y,
(XChar2b *) Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString) / 2);
if
(do_width) {
x += XTextWidth16(lastSubFontPtr->fontStructPtr,
(XChar2b *) Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString) / 2);
}
}
else
{
XDrawString(display, drawable, gc, x, y,
Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString));
if
(do_width) {
x += XTextWidth(lastSubFontPtr->fontStructPtr,
Tcl_DStringValue(&runString),
Tcl_DStringLength(&runString));
}
}
Tcl_DStringFree(&runString);
}
lastSubFontPtr = thisSubFontPtr;
source = p;
XSetFont(display, gc, lastSubFontPtr->fontStructPtr->fid);
if
(x > window_width) {
break
;
}
}
p = next;
}
if
(lastSubFontPtr != &fontPtr->subFontArray[0]) {
XSetFont(display, gc, fontPtr->subFontArray[0].fontStructPtr->fid);
}
if
(fontPtr->font.fa.underline != 0) {
XFillRectangle(display, drawable, gc, xStart,
y + fontPtr->underlinePos,
(unsigned) (x - xStart), (unsigned) fontPtr->barHeight);
}
if
(fontPtr->font.fa.overstrike != 0) {
y -= fontPtr->font.fm.descent + (fontPtr->font.fm.ascent) / 10;
XFillRectangle(display, drawable, gc, xStart, y,
(unsigned) (x - xStart), (unsigned) fontPtr->barHeight);
}
}
static
XFontStruct *
CreateClosestFont(tkwin, faPtr, xaPtr)
Tk_Window tkwin;
CONST TkFontAttributes *faPtr;
CONST TkXLFDAttributes *xaPtr;
{
FontAttributes want;
char
**nameList;
int
numNames, nameIdx;
Display *display;
XFontStruct *fontStructPtr;
int
bestIdx[2];
unsigned
int
bestScore[2];
want.fa = *faPtr;
want.xa = *xaPtr;
if
(want.xa.foundry == NULL) {
want.xa.foundry = Tk_GetUid(
"adobe"
);
}
if
(want.fa.family == NULL) {
want.fa.family = Tk_GetUid(
"fixed"
);
}
want.fa.size = -TkFontGetPixels(tkwin, faPtr->size);
if
(want.xa.charset == NULL || *want.xa.charset ==
'\0'
) {
want.xa.charset = Tk_GetUid(
"iso8859-1"
);
}
display = Tk_Display(tkwin);
nameList = ListFontOrAlias(display, want.fa.family, &numNames);
if
(numNames == 0) {
char
***fontFallbacks;
int
i, j;
char
*fallback;
fontFallbacks = TkFontGetFallbacks();
for
(i = 0; fontFallbacks[i] != NULL; i++) {
for
(j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
if
(strcasecmp(want.fa.family, fallback) == 0) {
break
;
}
}
if
(fallback != NULL) {
for
(j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
nameList = ListFontOrAlias(display, fallback, &numNames);
if
(numNames != 0) {
goto
found;
}
}
}
}
nameList = ListFonts(display,
"fixed"
, &numNames);
if
(numNames == 0) {
nameList = ListFonts(display,
"*"
, &numNames);
}
if
(numNames == 0) {
return
GetSystemFont(display);
}
}
found:
bestIdx[0] = -1;
bestIdx[1] = -1;
bestScore[0] = (unsigned
int
) -1;
bestScore[1] = (unsigned
int
) -1;
for
(nameIdx = 0; nameIdx < numNames; nameIdx++) {
FontAttributes got;
int
scalable;
unsigned
int
score;
if
(TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) {
continue
;
}
IdentifySymbolEncodings(&got);
scalable = (got.fa.size == 0);
score = RankAttributes(&want, &got,
' '
, nameList[nameIdx]);
if
(score < bestScore[scalable]) {
bestIdx[scalable] = nameIdx;
bestScore[scalable] = score;
}
if
(score == 0) {
break
;
}
}
fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx, bestScore, &nameIdx);
XFreeFontNames(nameList);
if
(fontStructPtr == NULL) {
return
GetSystemFont(display);
}
return
fontStructPtr;
}
static
void
InitFont(tkwin, fontStructPtr, fontPtr)
Tk_Window tkwin;
XFontStruct *fontStructPtr;
UnixFont *fontPtr;
{
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey,
sizeof
(ThreadSpecificData));
unsigned
long
value;
int
minHi, maxHi, minLo, maxLo, fixed, width, limit, i, n;
FontAttributes fa;
TkFontAttributes *faPtr;
TkFontMetrics *fmPtr;
SubFont *controlPtr, *subFontPtr;
char
*pageMap;
Display *display;
display = Tk_Display(tkwin);
GetFontAttributes(display, fontStructPtr, &fa);
minHi = fontStructPtr->min_byte1;
maxHi = fontStructPtr->max_byte1;
minLo = fontStructPtr->min_char_or_byte2;
maxLo = fontStructPtr->max_char_or_byte2;
fixed = 1;
if
(fontStructPtr->per_char != NULL) {
width = 0;
limit = (maxHi - minHi + 1) * (maxLo - minLo + 1);
for
(i = 0; i < limit; i++) {
n = fontStructPtr->per_char[i].width;
if
(n != 0) {
if
(width == 0) {
width = n;
}
else
if
(width != n) {
fixed = 0;
break
;
}
}
}
}
fontPtr->font.fid = fontStructPtr->fid;
faPtr = &fontPtr->font.fa;
faPtr->family = fa.fa.family;
#if 0
faPtr->size = TkFontGetPoints(tkwin, fa.fa.size);
#else
faPtr->size = -TkFontGetPixels(tkwin, fa.fa.size);
#endif
faPtr->weight = fa.fa.weight;
faPtr->slant = fa.fa.slant;
faPtr->underline = 0;
faPtr->overstrike = 0;
fmPtr = &fontPtr->font.fm;
fmPtr->ascent = fontStructPtr->ascent;
fmPtr->descent = fontStructPtr->descent;
fmPtr->maxWidth = fontStructPtr->max_bounds.width;
fmPtr->fixed = fixed;
fontPtr->display = display;
fontPtr->pixelSize = TkFontGetPixels(tkwin, fa.fa.size);
fontPtr->xa = fa.xa;
fontPtr->numSubFonts = 1;
fontPtr->subFontArray = fontPtr->staticSubFonts;
InitSubFont(display, fontStructPtr, 1, &fontPtr->subFontArray[0]);
fontPtr->controlSubFont = fontPtr->subFontArray[0];
subFontPtr = FindSubFontForChar(fontPtr,
'0'
, NULL);
controlPtr = &fontPtr->controlSubFont;
controlPtr->fontStructPtr = subFontPtr->fontStructPtr;
controlPtr->familyPtr = &tsdPtr->controlFamily;
controlPtr->fontMap = tsdPtr->controlFamily.fontMap;
pageMap = fontPtr->subFontArray[0].fontMap[0];
for
(i = 0; i < 256; i++) {
if
((minHi > 0) || (i < minLo) || (i > maxLo) ||
(((pageMap[i >> 3] >> (i & 7)) & 1) == 0)) {
n = 0;
}
else
if
(fontStructPtr->per_char == NULL) {
n = fontStructPtr->max_bounds.width;
}
else
{
n = fontStructPtr->per_char[i - minLo].width;
}
fontPtr->widths[i] = n;
}
if
(XGetFontProperty(fontStructPtr, XA_UNDERLINE_POSITION, &value)) {
fontPtr->underlinePos = value;
}
else
{
fontPtr->underlinePos = fontStructPtr->descent / 2;
}
fontPtr->barHeight = 0;
if
(XGetFontProperty(fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) {
fontPtr->barHeight = value;
}
if
(fontPtr->barHeight == 0) {
fontPtr->barHeight = fontPtr->widths[
'I'
] / 3;
if
(fontPtr->barHeight == 0) {
fontPtr->barHeight = 1;
}
}
if
(fontPtr->underlinePos + fontPtr->barHeight > fontStructPtr->descent) {
fontPtr->barHeight = fontStructPtr->descent - fontPtr->underlinePos;
if
(fontPtr->barHeight == 0) {
fontPtr->underlinePos--;
fontPtr->barHeight = 1;
}
}
}
static
void
ReleaseFont(fontPtr)
UnixFont *fontPtr;
{
int
i;
for
(i = 0; i < fontPtr->numSubFonts; i++) {
ReleaseSubFont(fontPtr->display, &fontPtr->subFontArray[i]);
}
if
(fontPtr->subFontArray != fontPtr->staticSubFonts) {
ckfree((
char
*) fontPtr->subFontArray);
}
}
static
void
InitSubFont(display, fontStructPtr, base, subFontPtr)
Display *display;
XFontStruct *fontStructPtr;
int
base;
SubFont *subFontPtr;
{
subFontPtr->fontStructPtr = fontStructPtr;
subFontPtr->familyPtr = AllocFontFamily(display, fontStructPtr, base);
subFontPtr->fontMap = subFontPtr->familyPtr->fontMap;
subFontPtr->name = NULL;
subFontPtr->trigger = -1;
}
static
void
ReleaseSubFont(display, subFontPtr)
Display *display;
SubFont *subFontPtr;
{
XFreeFont(display, subFontPtr->fontStructPtr);
FreeFontFamily(subFontPtr->familyPtr);
if
(subFontPtr->name) {
ckfree(subFontPtr->name);
}
}
static
FontFamily *
AllocFontFamily(display, fontStructPtr, base)
Display *display;
XFontStruct *fontStructPtr;
int
base;
{
FontFamily *familyPtr;
FontAttributes fa;
Tcl_Encoding encoding;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey,
sizeof
(ThreadSpecificData));
GetFontAttributes(display, fontStructPtr, &fa);
encoding = Tcl_GetEncoding(NULL, GetEncodingAlias(fa.xa.charset));
familyPtr = tsdPtr->fontFamilyList;
for
(; familyPtr != NULL; familyPtr = familyPtr->nextPtr) {
if
((familyPtr->faceName == fa.fa.family)
&& (familyPtr->foundry == fa.xa.foundry)
&& (familyPtr->encoding == encoding)) {
Tcl_FreeEncoding(encoding);
familyPtr->refCount++;
return
familyPtr;
}
}
familyPtr = (FontFamily *) ckalloc(
sizeof
(FontFamily));
memset
(familyPtr, 0,
sizeof
(FontFamily));
familyPtr->nextPtr = tsdPtr->fontFamilyList;
tsdPtr->fontFamilyList = familyPtr;
familyPtr->foundry = fa.xa.foundry;
familyPtr->faceName = fa.fa.family;
familyPtr->encoding = encoding;
#ifndef _LANG
familyPtr->refCount = 2;
#else
familyPtr->refCount = 1;
#endif
familyPtr->isTwoByteFont = !(
(fontStructPtr->min_byte1 == 0) &&
(fontStructPtr->max_byte1 == 0) &&
(fontStructPtr->max_char_or_byte2 < 256));
return
familyPtr;
}
static
void
FreeFontFamily(familyPtr)
FontFamily *familyPtr;
{
FontFamily **familyPtrPtr;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey,
sizeof
(ThreadSpecificData));
int
i;
if
(familyPtr == NULL) {
return
;
}
familyPtr->refCount--;
if
(familyPtr->refCount > 0) {
return
;
}
Tcl_FreeEncoding(familyPtr->encoding);
for
(i = 0; i < FONTMAP_PAGES; i++) {
if
(familyPtr->fontMap[i] != NULL) {
ckfree(familyPtr->fontMap[i]);
}
}
for
(familyPtrPtr = &tsdPtr->fontFamilyList; ; ) {
if
(*familyPtrPtr == familyPtr) {
*familyPtrPtr = familyPtr->nextPtr;
break
;
}
familyPtrPtr = &(*familyPtrPtr)->nextPtr;
}
ckfree((
char
*) familyPtr);
}
static
SubFont *
FindSubFontForChar(fontPtr, ch, fixSubFontPtrPtr)
UnixFont *fontPtr;
int
ch;
SubFont **fixSubFontPtrPtr;
{
int
i, j, k, numNames;
Tk_Uid faceName;
char
*fallback;
char
**aliases, **nameList, **anyFallbacks;
char
***fontFallbacks;
SubFont *subFontPtr;
Tcl_DString ds;
if
(FontMapLookup(&fontPtr->subFontArray[0], ch)) {
return
&fontPtr->subFontArray[0];
}
for
(i = 1; i < fontPtr->numSubFonts; i++) {
if
(FontMapLookup(&fontPtr->subFontArray[i], ch)) {
return
&fontPtr->subFontArray[i];
}
}
if
(FontMapLookup(&fontPtr->controlSubFont, ch)) {
return
&fontPtr->controlSubFont;
}
Tcl_DStringInit(&ds);
faceName = fontPtr->font.fa.family;
if
(SeenName(faceName, &ds) == 0) {
subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
if
(subFontPtr != NULL) {
goto
end;
}
}
aliases = TkFontGetAliasList(faceName);
subFontPtr = NULL;
fontFallbacks = TkFontGetFallbacks();
for
(i = 0; fontFallbacks[i] != NULL; i++) {
for
(j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
if
(strcasecmp(fallback, faceName) == 0) {
goto
tryfallbacks;
}
else
if
(aliases != NULL) {
for
(k = 0; aliases[k] != NULL; k++) {
if
(strcasecmp(fallback, aliases[k]) == 0) {
goto
tryfallbacks;
}
}
}
}
continue
;
tryfallbacks:
for
(j = 0; (fallback = fontFallbacks[i][j]) != NULL; j++) {
subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds,
fixSubFontPtrPtr);
if
(subFontPtr != NULL) {
goto
end;
}
}
}
anyFallbacks = TkFontGetGlobalClass();
for
(i = 0; (fallback = anyFallbacks[i]) != NULL; i++) {
subFontPtr = CanUseFallbackWithAliases(fontPtr, fallback, ch, &ds,
fixSubFontPtrPtr);
if
(subFontPtr != NULL) {
goto
end;
}
}
nameList = ListFonts(fontPtr->display,
"*"
, &numNames);
for
(i = 0; i < numNames; i++) {
fallback =
strchr
(nameList[i] + 1,
'-'
) + 1;
strchr
(fallback,
'-'
)[0] =
'\0'
;
if
(SeenName(fallback, &ds) == 0) {
subFontPtr = CanUseFallback(fontPtr, fallback, ch,
fixSubFontPtrPtr);
if
(subFontPtr != NULL) {
XFreeFontNames(nameList);
goto
end;
}
}
}
XFreeFontNames(nameList);
end:
Tcl_DStringFree(&ds);
if
(subFontPtr == NULL) {
subFontPtr = &fontPtr->controlSubFont;
FontMapInsert(subFontPtr, ch);
}
return
subFontPtr;
}
static
int
FontMapLookup(subFontPtr, ch)
SubFont *subFontPtr;
int
ch;
{
int
row, bitOffset;
row = ch >> FONTMAP_SHIFT;
if
(subFontPtr->fontMap[row] == NULL) {
FontMapLoadPage(subFontPtr, row);
}
bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
return
(subFontPtr->fontMap[row][bitOffset >> 3] >> (bitOffset & 7)) & 1;
}
static
void
FontMapInsert(subFontPtr, ch)
SubFont *subFontPtr;
int
ch;
{
int
row, bitOffset;
row = ch >> FONTMAP_SHIFT;
if
(subFontPtr->fontMap[row] == NULL) {
FontMapLoadPage(subFontPtr, row);
}
bitOffset = ch & (FONTMAP_BITSPERPAGE - 1);
subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
}
static
void
FontMapLoadPage(subFontPtr, row)
SubFont *subFontPtr;
int
row;
{
char
src[TCL_UTF_MAX], buf[16];
int
minHi, maxHi, minLo, maxLo, scale, checkLo;
int
i, end, bitOffset, isTwoByteFont, n;
Tcl_Encoding encoding;
XFontStruct *fontStructPtr;
XCharStruct *widths;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey,
sizeof
(ThreadSpecificData));
int
unicode = 0;
subFontPtr->fontMap[row] = (
char
*) ckalloc(FONTMAP_BITSPERPAGE / 8);
memset
(subFontPtr->fontMap[row], 0, FONTMAP_BITSPERPAGE / 8);
if
(subFontPtr->familyPtr == &tsdPtr->controlFamily) {
return
;
}
fontStructPtr = subFontPtr->fontStructPtr;
encoding = subFontPtr->familyPtr->encoding;
isTwoByteFont = subFontPtr->familyPtr->isTwoByteFont;
widths = fontStructPtr->per_char;
minHi = fontStructPtr->min_byte1;
maxHi = fontStructPtr->max_byte1;
minLo = fontStructPtr->min_char_or_byte2;
maxLo = fontStructPtr->max_char_or_byte2;
scale = maxLo - minLo + 1;
checkLo = minLo;
if
(! isTwoByteFont) {
if
(minLo < 32) {
checkLo = 32;
}
}
else
{
unicode =
strstr
(Tcl_GetEncodingName(encoding),
"ucs-2"
) ? 1 : 0;
}
end = (row + 1) << FONTMAP_SHIFT;
for
(i = row << FONTMAP_SHIFT; i < end; i++) {
int
hi, lo;
if
(unicode) {
buf[0] = (i >> 8);
buf[1] = (i & 0xFF);
}
else
if
(Tcl_UtfToExternal(NULL, encoding, src, Tcl_UniCharToUtf(i, src),
TCL_ENCODING_STOPONERROR, NULL, buf,
sizeof
(buf), NULL,
NULL, NULL) != TCL_OK) {
continue
;
}
if
(isTwoByteFont) {
hi = ((unsigned
char
*) buf)[0];
lo = ((unsigned
char
*) buf)[1];
}
else
{
hi = 0;
lo = ((unsigned
char
*) buf)[0];
}
n = (hi - minHi) * scale + lo - minLo;
if
((hi < minHi) || (hi > maxHi) || (lo < checkLo) || (lo > maxLo)) {
continue
;
}
if
((widths == NULL) || ((widths[n].width + widths[n].rbearing) != 0)) {
bitOffset = i & (FONTMAP_BITSPERPAGE - 1);
subFontPtr->fontMap[row][bitOffset >> 3] |= 1 << (bitOffset & 7);
}
}
}
static
SubFont *
CanUseFallbackWithAliases(fontPtr, faceName, ch, nameTriedPtr,
fixSubFontPtrPtr)
UnixFont *fontPtr;
char
*faceName;
int
ch;
Tcl_DString *nameTriedPtr;
SubFont **fixSubFontPtrPtr;
{
SubFont *subFontPtr;
char
**aliases;
int
i;
if
(SeenName(faceName, nameTriedPtr) == 0) {
subFontPtr = CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr);
if
(subFontPtr != NULL) {
return
subFontPtr;
}
}
aliases = TkFontGetAliasList(faceName);
if
(aliases != NULL) {
for
(i = 0; aliases[i] != NULL; i++) {
if
(SeenName(aliases[i], nameTriedPtr) == 0) {
subFontPtr = CanUseFallback(fontPtr, aliases[i], ch,
fixSubFontPtrPtr);
if
(subFontPtr != NULL) {
return
subFontPtr;
}
}
}
}
return
NULL;
}
static
int
SeenName(name, dsPtr)
CONST
char
*name;
Tcl_DString *dsPtr;
{
CONST
char
*seen, *end;
seen = Tcl_DStringValue(dsPtr);
end = seen + Tcl_DStringLength(dsPtr);
while
(seen < end) {
if
(strcasecmp(seen, name) == 0) {
return
1;
}
seen +=
strlen
(seen) + 1;
}
Tcl_DStringAppend(dsPtr, (
char
*) name, (
int
) (
strlen
(name) + 1));
return
0;
}
static
SubFont *
CanUseFallback(fontPtr, faceName, ch, fixSubFontPtrPtr)
UnixFont *fontPtr;
CONST
char
*faceName;
int
ch;
SubFont **fixSubFontPtrPtr;
{
int
i, nameIdx, numNames, srcLen;
Tk_Uid hateFoundry;
int
bestIdx[2];
CONST
char
*charset, *hateCharset;
unsigned
int
bestScore[2];
char
**nameList, **nameListOrig;
FontAttributes want, got;
char
src[TCL_UTF_MAX];
Display *display;
SubFont subFont;
XFontStruct *fontStructPtr;
Tcl_DString dsEncodings;
int
numEncodings;
Tcl_Encoding *encodingCachePtr;
display = fontPtr->display;
nameList = ListFonts(display, faceName, &numNames);
if
(numNames == 0) {
return
NULL;
}
nameListOrig = nameList;
srcLen = Tcl_UniCharToUtf(ch, src);
want.fa = fontPtr->font.fa;
want.xa = fontPtr->xa;
want.fa.family = Tk_GetUid(faceName);
want.fa.size = -fontPtr->pixelSize;
hateFoundry = NULL;
hateCharset = NULL;
numEncodings = 0;
Tcl_DStringInit(&dsEncodings);
charset = NULL;
retry:
bestIdx[0] = -1;
bestIdx[1] = -1;
bestScore[0] = (unsigned
int
) -1;
bestScore[1] = (unsigned
int
) -1;
for
(nameIdx = 0; nameIdx < numNames; nameIdx++) {
Tcl_Encoding encoding;
char
dst[16];
int
scalable, srcRead, dstWrote;
unsigned
int
score;
if
(nameList[nameIdx] == NULL) {
continue
;
}
if
(TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa) != TCL_OK) {
goto
crossout;
}
IdentifySymbolEncodings(&got);
charset = GetEncodingAlias(got.xa.charset);
if
(hateFoundry != NULL) {
if
((hateFoundry == got.xa.foundry)
&& (
strcmp
(hateCharset, charset) == 0)) {
if
(1 ||
strcmp
(hateCharset,
"ucs-2be"
) != 0)
goto
crossout;
}
}
else
{
if
(
strcmp
(charset,
"ucs-2be"
) == 0) {
if
((unsigned
int
) ch <= 0xffff)
goto
do_ranking;
goto
crossout;
}
for
(i = 0; i < fontPtr->numSubFonts; i++) {
encoding = fontPtr->subFontArray[i].familyPtr->encoding;
if
(
strcmp
(charset, Tcl_GetEncodingName(encoding)) == 0) {
goto
crossout;
}
}
}
do_ranking:
encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings);
for
(i = numEncodings; --i >= 0; encodingCachePtr++) {
encoding = *encodingCachePtr;
if
(
strcmp
(Tcl_GetEncodingName(encoding), charset) == 0) {
break
;
}
}
if
(i < 0) {
encoding = Tcl_GetEncoding(NULL, charset);
if
(encoding == NULL) {
goto
crossout;
}
Tcl_DStringAppend(&dsEncodings, (
char
*) &encoding,
sizeof
(encoding));
numEncodings++;
}
Tcl_UtfToExternal(NULL, encoding, src, srcLen,
TCL_ENCODING_STOPONERROR, NULL, dst,
sizeof
(dst), &srcRead,
&dstWrote, NULL);
if
(dstWrote == 0) {
goto
crossout;
}
scalable = (got.fa.size == 0);
score = RankAttributes(&want, &got, ch, nameList[nameIdx]);
if
(score < bestScore[scalable]) {
bestIdx[scalable] = nameIdx;
bestScore[scalable] = score;
}
if
(score == 0) {
break
;
}
else
if
(score == (unsigned
int
) -1) {
hateFoundry = got.xa.foundry;
hateCharset = charset;
goto
crossout;
}
else
if
(score == (unsigned
int
) -2) {
goto
crossout;
}
continue
;
crossout:
if
(nameList == nameListOrig) {
nameList = (
char
**) ckalloc(numNames *
sizeof
(
char
*));
memcpy
(nameList, nameListOrig, numNames *
sizeof
(
char
*));
}
nameList[nameIdx] = NULL;
}
fontStructPtr = GetScreenFont(display, &want, nameList, bestIdx, bestScore, &nameIdx);
encodingCachePtr = (Tcl_Encoding *) Tcl_DStringValue(&dsEncodings);
for
(i = numEncodings; --i >= 0; encodingCachePtr++) {
Tcl_FreeEncoding(*encodingCachePtr);
}
Tcl_DStringFree(&dsEncodings);
numEncodings = 0;
if
(fontStructPtr == NULL) {
if
(nameList != nameListOrig) {
ckfree((
char
*) nameList);
}
XFreeFontNames(nameListOrig);
return
NULL;
}
#ifdef _LANG
TkFontParseXLFD(nameList[nameIdx], &got.fa, &got.xa);
IdentifySymbolEncodings(&got);
#endif
InitSubFont(display, fontStructPtr, 0, &subFont);
if
(FontMapLookup(&subFont, ch) == 0) {
hateFoundry = got.xa.foundry;
hateCharset = GetEncodingAlias(got.xa.charset);
ReleaseSubFont(display, &subFont);
#ifdef _LANG
LangFontRank((unsigned
int
) -1, ch, nameList[nameIdx],
want.xa.foundry, &want.fa, want.xa.charset,
got.xa.foundry, &got.fa, got.xa.charset);
#endif
goto
retry;
}
#ifdef _LANG
LangFontRank(0, ch, nameList[nameIdx],
want.xa.foundry, &want.fa, want.xa.charset,
got.xa.foundry, &got.fa, got.xa.charset);
#endif
subFont.name = ckalloc(
strlen
(nameList[nameIdx])+1);
subFont.trigger = ch;
if
(subFont.name) {
strcpy
(subFont.name,nameList[nameIdx]);
}
if
(nameList != nameListOrig) {
ckfree((
char
*) nameList);
}
XFreeFontNames(nameListOrig);
if
(fontPtr->numSubFonts >= SUBFONT_SPACE) {
SubFont *newPtr;
newPtr = (SubFont *) ckalloc(
sizeof
(SubFont) * (fontPtr->numSubFonts + 1));
memcpy
((
char
*) newPtr, fontPtr->subFontArray,
fontPtr->numSubFonts *
sizeof
(SubFont));
if
(fixSubFontPtrPtr != NULL) {
register
SubFont *fixSubFontPtr = *fixSubFontPtrPtr;
if
(fixSubFontPtr != &fontPtr->controlSubFont) {
*fixSubFontPtrPtr =
newPtr + (fixSubFontPtr - fontPtr->subFontArray);
}
}
if
(fontPtr->subFontArray != fontPtr->staticSubFonts) {
ckfree((
char
*) fontPtr->subFontArray);
}
fontPtr->subFontArray = newPtr;
}
fontPtr->subFontArray[fontPtr->numSubFonts] = subFont;
fontPtr->numSubFonts++;
return
&fontPtr->subFontArray[fontPtr->numSubFonts - 1];
}
static
unsigned
int
RankAttributes(wantPtr, gotPtr, ch, name)
FontAttributes *wantPtr;
FontAttributes *gotPtr;
int
ch;
const
char
*name;
{
unsigned
int
penalty;
penalty = 0;
if
(gotPtr->xa.foundry != wantPtr->xa.foundry) {
penalty += 4500;
}
if
(gotPtr->fa.family != wantPtr->fa.family) {
penalty += 9000;
}
if
(gotPtr->fa.weight != wantPtr->fa.weight) {
penalty += 90;
}
if
(gotPtr->fa.slant != wantPtr->fa.slant) {
penalty += 60;
}
if
(gotPtr->xa.slant != wantPtr->xa.slant) {
penalty += 10;
}
if
(gotPtr->xa.setwidth != wantPtr->xa.setwidth) {
penalty += 1000;
}
if
(gotPtr->fa.size == 0) {
penalty += 10;
}
else
{
int
diff;
diff = (-gotPtr->fa.size - -wantPtr->fa.size);
if
(diff > 0) {
penalty += 600;
}
else
if
(diff < 0) {
penalty += 150;
diff = -diff;
}
penalty += 150 * diff;
}
if
(gotPtr->xa.charset != wantPtr->xa.charset) {
int
i;
CONST
char
*gotAlias, *wantAlias;
penalty += 65000;
gotAlias = GetEncodingAlias(gotPtr->xa.charset);
wantAlias = GetEncodingAlias(wantPtr->xa.charset);
if
(
strcmp
(gotAlias, wantAlias) != 0) {
penalty += 30000;
for
(i = 0; encodingList[i] != NULL; i++) {
if
(
strcmp
(gotAlias, encodingList[i]) == 0) {
penalty -= 30000;
break
;
}
penalty += 20000;
}
}
}
#ifdef _LANG
penalty = LangFontRank(penalty, ch, name,
wantPtr->xa.foundry,&wantPtr->fa, wantPtr->xa.charset,
gotPtr->xa.foundry,&gotPtr->fa, gotPtr->xa.charset);
#endif
return
penalty;
}
static
XFontStruct *
GetScreenFont(display, wantPtr, nameList, bestIdx, bestScore, indexPtr)
Display *display;
FontAttributes *wantPtr;
char
**nameList;
int
bestIdx[2];
unsigned
int
bestScore[2];
int
*indexPtr;
{
XFontStruct *fontStructPtr;
if
((bestIdx[0] < 0) && (bestIdx[1] < 0)) {
return
NULL;
}
fontStructPtr = NULL;
if
(bestScore[1] < bestScore[0] && bestScore[1] < (unsigned
int
) -2) {
char
*str, *rest;
char
buf[256];
int
i;
tryscale:
str = nameList[bestIdx[1]];
for
(i = 0; i < XLFD_PIXEL_SIZE; i++) {
str =
strchr
(str + 1,
'-'
);
}
rest = str;
for
(i = XLFD_PIXEL_SIZE; i < XLFD_CHARSET; i++) {
rest =
strchr
(rest + 1,
'-'
);
}
*str =
'\0'
;
sprintf
(buf,
"%.200s-%d-*-*-*-*-*%s"
, nameList[bestIdx[1]],
-wantPtr->fa.size, rest);
*str =
'-'
;
fontStructPtr = XLoadQueryFont(display, buf);
if
(fontStructPtr != NULL) {
*indexPtr = bestIdx[1];
}
bestScore[1] = (unsigned
int
) -1;
}
if
(fontStructPtr == NULL && bestScore[0] < (unsigned
int
) -2) {
fontStructPtr = XLoadQueryFont(display, nameList[bestIdx[0]]);
if
(fontStructPtr == NULL) {
if
(bestScore[1] < (unsigned
int
) -2) {
goto
tryscale;
}
return
GetSystemFont(display);
}
else
{
*indexPtr = bestIdx[0];
}
}
return
fontStructPtr;
}
static
XFontStruct *
GetSystemFont(display)
Display *display;
{
XFontStruct *fontStructPtr;
fontStructPtr = XLoadQueryFont(display,
"fixed"
);
if
(fontStructPtr == NULL) {
fontStructPtr = XLoadQueryFont(display,
"*"
);
if
(fontStructPtr == NULL) {
panic(
"TkpGetFontFromAttributes: cannot get any font"
);
}
}
return
fontStructPtr;
}
static
int
GetFontAttributes(display, fontStructPtr, faPtr)
Display *display;
XFontStruct *fontStructPtr;
FontAttributes *faPtr;
{
unsigned
long
value;
char
*name;
if
((XGetFontProperty(fontStructPtr, XA_FONT, &value) != False) &&
(value != 0)) {
name = XGetAtomName(display, (Atom) value);
if
(TkFontParseXLFD(name, &faPtr->fa, &faPtr->xa) != TCL_OK) {
faPtr->fa.family = Tk_GetUid(name);
faPtr->xa.foundry = Tk_GetUid(
""
);
faPtr->xa.charset = Tk_GetUid(
""
);
}
XFree(name);
}
else
{
TkInitFontAttributes(&faPtr->fa);
TkInitXLFDAttributes(&faPtr->xa);
faPtr->fa.family = Tk_GetUid(
""
);
faPtr->xa.foundry = Tk_GetUid(
""
);
faPtr->xa.charset = Tk_GetUid(
""
);
}
return
IdentifySymbolEncodings(faPtr);
}
static
char
**
ListFonts(display, faceName, numNamesPtr)
Display *display;
CONST
char
*faceName;
int
*numNamesPtr;
{
char
buf[256];
sprintf
(buf,
"-*-%.80s-*-*-*-*-*-*-*-*-*-*-*-*"
, faceName);
return
XListFonts(display, buf, 10000, numNamesPtr);
}
static
char
**
ListFontOrAlias(display, faceName, numNamesPtr)
Display *display;
CONST
char
*faceName;
int
*numNamesPtr;
{
char
**nameList, **aliases;
int
i;
nameList = ListFonts(display, faceName, numNamesPtr);
if
(nameList != NULL) {
return
nameList;
}
aliases = TkFontGetAliasList(faceName);
if
(aliases != NULL) {
for
(i = 0; aliases[i] != NULL; i++) {
nameList = ListFonts(display, aliases[i], numNamesPtr);
if
(nameList != NULL) {
return
nameList;
}
}
}
*numNamesPtr = 0;
return
NULL;
}
static
int
IdentifySymbolEncodings(faPtr)
FontAttributes *faPtr;
{
int
i, j;
char
**aliases, **symbolClass;
symbolClass = TkFontGetSymbolClass();
for
(i = 0; symbolClass[i] != NULL; i++) {
if
(strcasecmp(faPtr->fa.family, symbolClass[i]) == 0) {
faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(symbolClass[i]));
return
1;
}
aliases = TkFontGetAliasList(symbolClass[i]);
for
(j = 0; (aliases != NULL) && (aliases[j] != NULL); j++) {
if
(strcasecmp(faPtr->fa.family, aliases[j]) == 0) {
faPtr->xa.charset = Tk_GetUid(GetEncodingAlias(aliases[j]));
return
1;
}
}
}
return
0;
}
static
CONST
char
*
GetEncodingAlias(name)
CONST
char
*name;
{
EncodingAlias *aliasPtr;
for
(aliasPtr = encodingAliases; aliasPtr->aliasPattern != NULL; ) {
if
(Tcl_StringMatch((
char
*) name, aliasPtr->aliasPattern)) {
return
aliasPtr->realName;
}
aliasPtr++;
}
return
name;
}
#endif /* USE_XFT_FONTS */