4 * This file maintains a database of fonts for the Tk toolkit.
5 * It also provides several utility procedures for measuring and
8 * Copyright (c) 1990-1994 The Regents of the University of California.
9 * Copyright (c) 1994-1998 Sun Microsystems, Inc.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
22 * The following structure is used to keep track of all the fonts that
23 * exist in the current application. It must be stored in the
24 * TkMainInfo for the application.
27 typedef struct TkFontInfo {
28 Tcl_HashTable fontCache; /* Map a string to an existing Tk_Font.
29 * Keys are string font names, values are
31 Tcl_HashTable namedTable; /* Map a name to a set of attributes for a
32 * font, used when constructing a Tk_Font from
33 * a named font description. Keys are
34 * strings, values are NamedFont pointers. */
35 TkMainInfo *mainPtr; /* Application that owns this structure. */
36 int updatePending; /* Non-zero when a World Changed event has
37 * already been queued to handle a change to
42 * The following data structure is used to keep track of the font attributes
43 * for each named font that has been defined. The named font is only deleted
44 * when the last reference to it goes away.
47 typedef struct NamedFont {
48 int refCount; /* Number of users of named font. */
49 int deletePending; /* Non-zero if font should be deleted when
50 * last reference goes away. */
51 TkFontAttributes fa; /* Desired attributes for named font. */
55 * The following two structures are used to keep track of string
56 * measurement information when using the text layout facilities.
58 * A LayoutChunk represents a contiguous range of text that can be measured
59 * and displayed by low-level text calls. In general, chunks will be
60 * delimited by newlines and tabs. Low-level, platform-specific things
61 * like kerning and non-integer character widths may occur between the
62 * characters in a single chunk, but not between characters in different
65 * A TextLayout is a collection of LayoutChunks. It can be displayed with
66 * respect to any origin. It is the implementation of the Tk_TextLayout
70 typedef struct LayoutChunk {
71 CONST char *start; /* Pointer to simple string to be displayed.
72 * This is a pointer into the TkTextLayout's
74 int numBytes; /* The number of bytes in this chunk. */
75 int numChars; /* The number of characters in this chunk. */
76 int numDisplayChars; /* The number of characters to display when
77 * this chunk is displayed. Can be less than
78 * numChars if extra space characters were
79 * absorbed by the end of the chunk. This
80 * will be < 0 if this is a chunk that is
81 * holding a tab or newline. */
82 int x, y; /* The origin of the first character in this
83 * chunk with respect to the upper-left hand
84 * corner of the TextLayout. */
85 int totalWidth; /* Width in pixels of this chunk. Used
86 * when hit testing the invisible spaces at
87 * the end of a chunk. */
88 int displayWidth; /* Width in pixels of the displayable
89 * characters in this chunk. Can be less than
90 * width if extra space characters were
91 * absorbed by the end of the chunk. */
94 typedef struct TextLayout {
95 Tk_Font tkfont; /* The font used when laying out the text. */
96 CONST char *string; /* The string that was layed out. */
97 int width; /* The maximum width of all lines in the
99 int numChunks; /* Number of chunks actually used in
100 * following array. */
101 LayoutChunk chunks[1]; /* Array of chunks. The actual size will
102 * be maxChunks. THIS FIELD MUST BE THE LAST
103 * IN THE STRUCTURE. */
107 * The following structures are used as two-way maps between the values for
108 * the fields in the TkFontAttributes structure and the strings used in
109 * Tcl, when parsing both option-value format and style-list format font
113 static TkStateMap weightMap[] = {
114 {TK_FW_NORMAL, "normal"},
115 {TK_FW_BOLD, "bold"},
116 {TK_FW_UNKNOWN, NULL}
119 static TkStateMap slantMap[] = {
120 {TK_FS_ROMAN, "roman"},
121 {TK_FS_ITALIC, "italic"},
122 {TK_FS_UNKNOWN, NULL}
125 static TkStateMap underlineMap[] = {
130 static TkStateMap overstrikeMap[] = {
136 * The following structures are used when parsing XLFD's into a set of
140 static TkStateMap xlfdWeightMap[] = {
141 {TK_FW_NORMAL, "normal"},
142 {TK_FW_NORMAL, "medium"},
143 {TK_FW_NORMAL, "book"},
144 {TK_FW_NORMAL, "light"},
145 {TK_FW_BOLD, "bold"},
146 {TK_FW_BOLD, "demi"},
147 {TK_FW_BOLD, "demibold"},
148 {TK_FW_NORMAL, NULL} /* Assume anything else is "normal". */
151 static TkStateMap xlfdSlantMap[] = {
154 {TK_FS_OBLIQUE, "o"},
155 {TK_FS_ROMAN, NULL} /* Assume anything else is "roman". */
158 static TkStateMap xlfdSetwidthMap[] = {
159 {TK_SW_NORMAL, "normal"},
160 {TK_SW_CONDENSE, "narrow"},
161 {TK_SW_CONDENSE, "semicondensed"},
162 {TK_SW_CONDENSE, "condensed"},
163 {TK_SW_UNKNOWN, NULL}
167 * The following structure and defines specify the valid builtin options
168 * when configuring a set of font attributes.
171 static CONST char *fontOpt[] = {
181 #define FONT_FAMILY 0
183 #define FONT_WEIGHT 2
185 #define FONT_UNDERLINE 4
186 #define FONT_OVERSTRIKE 5
187 #define FONT_NUMFIELDS 6
190 * Hardcoded font aliases. These are used to describe (mostly) identical
191 * fonts whose names differ from platform to platform. If the
192 * user-supplied font name matches any of the names in one of the alias
193 * lists, the other names in the alias list are also automatically tried.
196 static char *timesAliases[] = {
198 "Times New Roman", /* Windows. */
199 "New York", /* Mac. */
203 static char *helveticaAliases[] = {
204 "Helvetica", /* Unix. */
205 "Arial", /* Windows. */
210 static char *courierAliases[] = {
211 "Courier", /* Unix and Mac. */
212 "Courier New", /* Windows. */
216 static char *minchoAliases[] = {
217 "mincho", /* Unix. */
218 "\357\274\255\357\274\263 \346\230\216\346\234\235",
219 /* Windows (MS mincho). */
220 "\346\234\254\346\230\216\346\234\235\342\210\222\357\274\255",
221 /* Mac (honmincho-M). */
225 static char *gothicAliases[] = {
226 "gothic", /* Unix. */
227 "\357\274\255\357\274\263 \343\202\264\343\202\267\343\203\203\343\202\257",
228 /* Windows (MS goshikku). */
229 "\344\270\270\343\202\264\343\202\267\343\203\203\343\202\257\342\210\222\357\274\255",
230 /* Mac (goshikku-M). */
234 static char *dingbatsAliases[] = {
235 "dingbats", "zapfdingbats", "itc zapfdingbats",
238 "zapf dingbats", /* Mac. */
242 static char **fontAliases[] = {
253 * Hardcoded font classes. If the character cannot be found in the base
254 * font, the classes are examined in order to see if some other similar
255 * font should be examined also.
258 static char *systemClass[] = {
261 "chicago", "osaka", "sistemny", /* Mac. */
265 static char *serifClass[] = {
266 "times", "palatino", "mincho", /* All platforms. */
267 "song ti", /* Unix. */
268 "ms serif", "simplified arabic", /* Windows. */
269 "latinski", /* Mac. */
273 static char *sansClass[] = {
274 "helvetica", "gothic", /* All platforms. */
276 "ms sans serif", "traditional arabic",
278 "bastion", /* Mac. */
282 static char *monoClass[] = {
283 "courier", "gothic", /* All platforms. */
284 "fangsong ti", /* Unix. */
285 "simplified arabic fixed", /* Windows. */
286 "monaco", "pryamoy", /* Mac. */
290 static char *symbolClass[] = {
291 "symbol", "dingbats", "wingdings", NULL
294 static char **fontFallbacks[] = {
304 * Global fallbacks. If the character could not be found in the preferred
305 * fallback list, this list is examined. If the character still cannot be
306 * found, all font families in the system are examined.
309 static char *globalFontClass[] = {
310 "symbol", /* All platforms. */
312 "lucida sans unicode", /* Windows. */
313 "bitstream cyberbit", /* Windows popular CJK font */
314 "chicago", /* Mac. */
318 #define GetFontAttributes(tkfont) \
319 ((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa)
321 #define GetFontMetrics(tkfont) \
322 ((CONST TkFontMetrics *) &((TkFont *) (tkfont))->fm)
325 static int ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp,
326 Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[],
327 TkFontAttributes *faPtr));
328 static int CreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp,
329 Tk_Window tkwin, CONST char *name,
330 TkFontAttributes *faPtr));
331 static void DupFontObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,
332 Tcl_Obj *dupObjPtr));
333 static int FieldSpecified _ANSI_ARGS_((CONST char *field));
334 static void FreeFontObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));
335 static int GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp,
336 CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr));
337 static LayoutChunk * NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr,
338 int *maxPtr, CONST char *start, int numChars,
339 int curX, int newX, int y));
340 static int ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp,
341 Tk_Window tkwin, Tcl_Obj *objPtr,
342 TkFontAttributes *faPtr));
343 static void RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr));
344 static int SetFontFromAny _ANSI_ARGS_((Tcl_Interp *interp,
346 static void TheWorldHasChanged _ANSI_ARGS_((
347 ClientData clientData));
348 static void UpdateDependentFonts _ANSI_ARGS_((TkFontInfo *fiPtr,
349 Tk_Window tkwin, Tcl_HashEntry *namedHashPtr));
352 * The following structure defines the implementation of the "font" Tcl
353 * object, used for drawing. The internalRep.twoPtrValue.ptr1 field of
354 * each font object points to the TkFont structure for the font, or
358 Tcl_ObjType tkFontObjType = {
360 FreeFontObjProc, /* freeIntRepProc */
361 DupFontObjProc, /* dupIntRepProc */
362 NULL, /* updateStringProc */
363 SetFontFromAny /* setFromAnyProc */
368 *---------------------------------------------------------------------------
372 * This procedure is called when an application is created. It
373 * initializes all the structures that are used by the font
374 * package on a per application basis.
377 * Stores a token in the mainPtr to hold information needed by this
378 * package on a per application basis.
383 *---------------------------------------------------------------------------
386 TkFontPkgInit(mainPtr)
387 TkMainInfo *mainPtr; /* The application being created. */
391 fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo));
392 Tcl_InitHashTable(&fiPtr->fontCache, TCL_STRING_KEYS);
393 Tcl_InitHashTable(&fiPtr->namedTable, TCL_STRING_KEYS);
394 fiPtr->mainPtr = mainPtr;
395 fiPtr->updatePending = 0;
396 mainPtr->fontInfoPtr = fiPtr;
398 TkpFontPkgInit(mainPtr);
402 *---------------------------------------------------------------------------
406 * This procedure is called when an application is deleted. It
407 * deletes all the structures that were used by the font package
408 * for this application.
416 *---------------------------------------------------------------------------
420 TkFontPkgFree(mainPtr)
421 TkMainInfo *mainPtr; /* The application being deleted. */
424 Tcl_HashEntry *hPtr, *searchPtr;
425 Tcl_HashSearch search;
428 fiPtr = mainPtr->fontInfoPtr;
431 for (searchPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);
433 searchPtr = Tcl_NextHashEntry(&search)) {
435 fprintf(stderr, "Font %s still in cache.\n",
436 Tcl_GetHashKey(&fiPtr->fontCache, searchPtr));
440 panic("TkFontPkgFree: all fonts should have been freed already");
443 Tcl_DeleteHashTable(&fiPtr->fontCache);
445 hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
446 while (hPtr != NULL) {
447 ckfree((char *) Tcl_GetHashValue(hPtr));
448 hPtr = Tcl_NextHashEntry(&search);
450 Tcl_DeleteHashTable(&fiPtr->namedTable);
451 if (fiPtr->updatePending != 0) {
452 Tcl_CancelIdleCall(TheWorldHasChanged, (ClientData) fiPtr);
454 ckfree((char *) fiPtr);
458 *---------------------------------------------------------------------------
462 * This procedure is implemented to process the "font" Tcl command.
463 * See the user documentation for details on what it does.
466 * A standard Tcl result.
469 * See the user documentation.
471 *----------------------------------------------------------------------
475 Tk_FontObjCmd(clientData, interp, objc, objv)
476 ClientData clientData; /* Main window associated with interpreter. */
477 Tcl_Interp *interp; /* Current interpreter. */
478 int objc; /* Number of arguments. */
479 Tcl_Obj *CONST objv[]; /* Argument objects. */
484 static CONST char *optionStrings[] = {
485 "actual", "configure", "create", "delete",
486 "families", "measure", "metrics", "names",
490 FONT_ACTUAL, FONT_CONFIGURE, FONT_CREATE, FONT_DELETE,
491 FONT_FAMILIES, FONT_MEASURE, FONT_METRICS, FONT_NAMES
494 tkwin = (Tk_Window) clientData;
495 fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
498 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
501 if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
506 switch ((enum options) index) {
511 CONST TkFontAttributes *faPtr;
513 skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
517 if ((objc < 3) || (objc - skip > 4)) {
518 Tcl_WrongNumArgs(interp, 2, objv,
519 "font ?-displayof window? ?option?");
522 tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
523 if (tkfont == NULL) {
528 faPtr = GetFontAttributes(tkfont);
533 result = GetAttributeInfoObj(interp, faPtr, objPtr);
537 case FONT_CONFIGURE: {
542 Tcl_HashEntry *namedHashPtr;
545 Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?");
548 string = Tcl_GetString(objv[2]);
549 namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
550 nfPtr = NULL; /* lint. */
551 if (namedHashPtr != NULL) {
552 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
554 if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) {
555 Tcl_AppendResult(interp, "named font \"", string,
556 "\" doesn't exist", NULL);
561 } else if (objc == 4) {
564 result = ConfigAttributesObj(interp, tkwin, objc - 3,
565 objv + 3, &nfPtr->fa);
566 UpdateDependentFonts(fiPtr, tkwin, namedHashPtr);
569 return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr);
574 char buf[16 + TCL_INTEGER_SPACE];
576 Tcl_HashEntry *namedHashPtr;
582 name = Tcl_GetString(objv[2]);
583 if (name[0] == '-') {
589 * No font name specified. Generate one of the form "fontX".
593 sprintf(buf, "font%d", i);
594 namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, buf);
595 if (namedHashPtr == NULL) {
602 TkInitFontAttributes(&fa);
603 if (ConfigAttributesObj(interp, tkwin, objc - skip, objv + skip,
607 if (CreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) {
610 Tcl_AppendResult(interp, name, NULL);
617 Tcl_HashEntry *namedHashPtr;
620 * Delete the named font. If there are still widgets using this
621 * font, then it isn't deleted right away.
625 Tcl_WrongNumArgs(interp, 2, objv, "fontname ?fontname ...?");
628 for (i = 2; i < objc; i++) {
629 string = Tcl_GetString(objv[i]);
630 namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
631 if (namedHashPtr == NULL) {
632 Tcl_AppendResult(interp, "named font \"", string,
633 "\" doesn't exist", (char *) NULL);
636 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
637 if (nfPtr->refCount != 0) {
638 nfPtr->deletePending = 1;
640 Tcl_DeleteHashEntry(namedHashPtr);
641 ckfree((char *) nfPtr);
646 case FONT_FAMILIES: {
649 skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
653 if (objc - skip != 2) {
654 Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?");
657 TkpGetFontFamilies(interp, tkwin);
666 skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
670 if (objc - skip != 4) {
671 Tcl_WrongNumArgs(interp, 2, objv,
672 "font ?-displayof window? text");
675 tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
676 if (tkfont == NULL) {
679 string = Tcl_GetStringFromObj(objv[3 + skip], &length);
680 resultPtr = Tcl_GetObjResult(interp);
681 Tcl_SetIntObj(resultPtr, Tk_TextWidth(tkfont, string, length));
688 CONST TkFontMetrics *fmPtr;
689 static CONST char *switches[] = {
690 "-ascent", "-descent", "-linespace", "-fixed", NULL
693 skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
697 if ((objc < 3) || ((objc - skip) > 4)) {
698 Tcl_WrongNumArgs(interp, 2, objv,
699 "font ?-displayof window? ?option?");
702 tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
703 if (tkfont == NULL) {
708 fmPtr = GetFontMetrics(tkfont);
710 char buf[64 + TCL_INTEGER_SPACE * 4];
712 sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d",
713 fmPtr->ascent, fmPtr->descent,
714 fmPtr->ascent + fmPtr->descent,
716 Tcl_AppendResult(interp, buf, NULL);
718 if (Tcl_GetIndexFromObj(interp, objv[3], switches,
719 "metric", 0, &index) != TCL_OK) {
723 i = 0; /* Needed only to prevent compiler
726 case 0: i = fmPtr->ascent; break;
727 case 1: i = fmPtr->descent; break;
728 case 2: i = fmPtr->ascent + fmPtr->descent; break;
729 case 3: i = fmPtr->fixed; break;
731 Tcl_SetIntObj(Tcl_GetObjResult(interp), i);
739 Tcl_HashSearch search;
740 Tcl_HashEntry *namedHashPtr;
741 Tcl_Obj *strPtr, *resultPtr;
744 Tcl_WrongNumArgs(interp, 1, objv, "names");
747 resultPtr = Tcl_GetObjResult(interp);
748 namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
749 while (namedHashPtr != NULL) {
750 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
751 if (nfPtr->deletePending == 0) {
752 string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr);
753 strPtr = Tcl_NewStringObj(string, -1);
754 Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
756 namedHashPtr = Tcl_NextHashEntry(&search);
765 *---------------------------------------------------------------------------
767 * UpdateDependentFonts, TheWorldHasChanged, RecomputeWidgets --
769 * Called when the attributes of a named font changes. Updates all
770 * the instantiated fonts that depend on that named font and then
771 * uses the brute force approach and prepares every widget to
772 * recompute its geometry.
778 * Things get queued for redisplay.
780 *---------------------------------------------------------------------------
784 UpdateDependentFonts(fiPtr, tkwin, namedHashPtr)
785 TkFontInfo *fiPtr; /* Info about application's fonts. */
786 Tk_Window tkwin; /* A window in the application. */
787 Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */
789 Tcl_HashEntry *cacheHashPtr;
790 Tcl_HashSearch search;
794 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
795 if (nfPtr->refCount == 0) {
797 * Well nobody's using this named font, so don't have to tell
798 * any widgets to recompute themselves.
804 cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);
805 while (cacheHashPtr != NULL) {
806 for (fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
807 fontPtr != NULL; fontPtr = fontPtr->nextPtr) {
808 if (fontPtr->namedHashPtr == namedHashPtr) {
809 TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa);
810 if (fiPtr->updatePending == 0) {
811 fiPtr->updatePending = 1;
812 Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr);
816 cacheHashPtr = Tcl_NextHashEntry(&search);
821 TheWorldHasChanged(clientData)
822 ClientData clientData; /* Info about application's fonts. */
826 fiPtr = (TkFontInfo *) clientData;
827 fiPtr->updatePending = 0;
829 RecomputeWidgets(fiPtr->mainPtr->winPtr);
833 RecomputeWidgets(winPtr)
834 TkWindow *winPtr; /* Window to which command is sent. */
836 Tk_ClassWorldChangedProc *proc;
837 proc = Tk_GetClassProc(winPtr->classProcsPtr, worldChangedProc);
839 (*proc)(winPtr->instanceData);
843 * Notify all the descendants of this window that the world has changed.
845 * This could be done recursively or iteratively. The recursive version
846 * is easier to implement and understand, and typically, windows with a
847 * -font option will be leaf nodes in the widget heirarchy (buttons,
848 * labels, etc.), so the recursion depth will be shallow.
850 * However, the additional overhead of the recursive calls may become
851 * a performance problem if typical usage alters such that -font'ed widgets
852 * appear high in the heirarchy, causing deep recursion. This could happen
853 * with text widgets, or more likely with the (not yet existant) labeled
854 * frame widget. With these widgets it is possible, even likely, that a
855 * -font'ed widget (text or labeled frame) will not be a leaf node, but
856 * will instead have many descendants. If this is ever found to cause
857 * a performance problem, it may be worth investigating an iterative
858 * version of the code below.
860 for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) {
861 RecomputeWidgets(winPtr);
866 *---------------------------------------------------------------------------
870 * Create the specified named font with the given attributes in the
871 * named font table associated with the interp.
874 * Returns TCL_OK if the font was successfully created, or TCL_ERROR
875 * if the named font already existed. If TCL_ERROR is returned, an
876 * error message is left in the interp's result.
879 * Assume there used to exist a named font by the specified name, and
880 * that the named font had been deleted, but there were still some
881 * widgets using the named font at the time it was deleted. If a
882 * new named font is created with the same name, all those widgets
883 * that were using the old named font will be redisplayed using
884 * the new named font's attributes.
886 *---------------------------------------------------------------------------
890 CreateNamedFont(interp, tkwin, name, faPtr)
891 Tcl_Interp *interp; /* Interp for error return. */
892 Tk_Window tkwin; /* A window associated with interp. */
893 CONST char *name; /* Name for the new named font. */
894 TkFontAttributes *faPtr; /* Attributes for the new named font. */
897 Tcl_HashEntry *namedHashPtr;
901 fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
903 namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new);
906 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
907 if (nfPtr->deletePending == 0) {
908 Tcl_ResetResult(interp);
909 Tcl_AppendResult(interp, "named font \"", name,
910 "\" already exists", (char *) NULL);
915 * Recreating a named font with the same name as a previous
916 * named font. Some widgets were still using that named
917 * font, so they need to get redisplayed.
921 nfPtr->deletePending = 0;
922 UpdateDependentFonts(fiPtr, tkwin, namedHashPtr);
926 nfPtr = (NamedFont *) ckalloc(sizeof(NamedFont));
927 nfPtr->deletePending = 0;
928 Tcl_SetHashValue(namedHashPtr, nfPtr);
931 nfPtr->deletePending = 0;
936 *---------------------------------------------------------------------------
940 * Given a string description of a font, map the description to a
941 * corresponding Tk_Font that represents the font.
944 * The return value is token for the font, or NULL if an error
945 * prevented the font from being created. If NULL is returned, an
946 * error message will be left in the interp's result.
949 * The font is added to an internal database with a reference
950 * count. For each call to this procedure, there should eventually
951 * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the
952 * database is cleaned up when fonts aren't in use anymore.
954 *---------------------------------------------------------------------------
958 Tk_GetFont(interp, tkwin, string)
959 Tcl_Interp *interp; /* Interp for database and error return. */
960 Tk_Window tkwin; /* For display on which font will be used. */
961 CONST char *string; /* String describing font, as: named font,
962 * native format, or parseable string. */
967 strPtr = Tcl_NewStringObj((char *) string, -1);
968 Tcl_IncrRefCount(strPtr);
969 tkfont = Tk_AllocFontFromObj(interp, tkwin, strPtr);
970 Tcl_DecrRefCount(strPtr);
975 *---------------------------------------------------------------------------
977 * Tk_AllocFontFromObj --
979 * Given a string description of a font, map the description to a
980 * corresponding Tk_Font that represents the font.
983 * The return value is token for the font, or NULL if an error
984 * prevented the font from being created. If NULL is returned, an
985 * error message will be left in interp's result object.
988 * The font is added to an internal database with a reference
989 * count. For each call to this procedure, there should eventually
990 * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the
991 * database is cleaned up when fonts aren't in use anymore.
993 *---------------------------------------------------------------------------
997 Tk_AllocFontFromObj(interp, tkwin, objPtr)
998 Tcl_Interp *interp; /* Interp for database and error return. */
999 Tk_Window tkwin; /* For screen on which font will be used. */
1000 Tcl_Obj *objPtr; /* Object describing font, as: named font,
1001 * native format, or parseable string. */
1004 Tcl_HashEntry *cacheHashPtr, *namedHashPtr;
1005 TkFont *fontPtr, *firstFontPtr, *oldFontPtr;
1009 fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
1010 if (objPtr->typePtr != &tkFontObjType) {
1011 SetFontFromAny(interp, objPtr);
1014 oldFontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
1016 if (oldFontPtr != NULL) {
1017 if (oldFontPtr->resourceRefCount == 0) {
1019 * This is a stale reference: it refers to a TkFont that's
1020 * no longer in use. Clear the reference.
1023 FreeFontObjProc(objPtr);
1025 } else if (Tk_Screen(tkwin) == oldFontPtr->screen) {
1026 oldFontPtr->resourceRefCount++;
1027 return (Tk_Font) oldFontPtr;
1032 * Next, search the list of fonts that have the name we want, to see
1033 * if one of them is for the right screen.
1037 if (oldFontPtr != NULL) {
1038 cacheHashPtr = oldFontPtr->cacheHashPtr;
1039 FreeFontObjProc(objPtr);
1041 cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache,
1042 Tcl_GetString(objPtr), &new);
1044 firstFontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
1045 for (fontPtr = firstFontPtr; (fontPtr != NULL);
1046 fontPtr = fontPtr->nextPtr) {
1047 if (Tk_Screen(tkwin) == fontPtr->screen) {
1048 fontPtr->resourceRefCount++;
1049 fontPtr->objRefCount++;
1050 objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
1051 return (Tk_Font) fontPtr;
1056 * The desired font isn't in the table. Make a new one.
1059 namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable,
1060 Tcl_GetString(objPtr));
1061 if (namedHashPtr != NULL) {
1063 * Construct a font based on a named font.
1066 nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
1069 fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &nfPtr->fa);
1075 fontPtr = TkpGetNativeFont(tkwin, Tcl_GetString(objPtr));
1076 if (fontPtr == NULL) {
1077 TkFontAttributes fa;
1078 Tcl_Obj *dupObjPtr = Tcl_DuplicateObj(objPtr);
1080 if (ParseFontNameObj(interp, tkwin, dupObjPtr, &fa) != TCL_OK) {
1082 Tcl_DeleteHashEntry(cacheHashPtr);
1084 Tcl_DecrRefCount(dupObjPtr);
1087 Tcl_DecrRefCount(dupObjPtr);
1090 * String contained the attributes inline.
1093 fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa);
1097 fontPtr->resourceRefCount = 1;
1098 fontPtr->objRefCount = 1;
1099 fontPtr->cacheHashPtr = cacheHashPtr;
1100 fontPtr->namedHashPtr = namedHashPtr;
1101 fontPtr->screen = Tk_Screen(tkwin);
1102 fontPtr->nextPtr = firstFontPtr;
1103 Tcl_SetHashValue(cacheHashPtr, fontPtr);
1105 Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, -1, 0, &fontPtr->tabWidth);
1106 if (fontPtr->tabWidth == 0) {
1107 fontPtr->tabWidth = fontPtr->fm.maxWidth;
1109 fontPtr->tabWidth *= 8;
1112 * Make sure the tab width isn't zero (some fonts may not have enough
1113 * information to set a reasonable tab width).
1116 if (fontPtr->tabWidth == 0) {
1117 fontPtr->tabWidth = 1;
1121 * Get information used for drawing underlines in generic code on a
1122 * non-underlined font.
1125 descent = fontPtr->fm.descent;
1126 fontPtr->underlinePos = descent / 2;
1127 fontPtr->underlineHeight = TkFontGetPixels(tkwin, fontPtr->fa.size) / 10;
1128 if (fontPtr->underlineHeight == 0) {
1129 fontPtr->underlineHeight = 1;
1131 if (fontPtr->underlinePos + fontPtr->underlineHeight > descent) {
1133 * If this set of values would cause the bottom of the underline
1134 * bar to stick below the descent of the font, jack the underline
1138 fontPtr->underlineHeight = descent - fontPtr->underlinePos;
1139 if (fontPtr->underlineHeight == 0) {
1140 fontPtr->underlinePos--;
1141 fontPtr->underlineHeight = 1;
1145 objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
1146 return (Tk_Font) fontPtr;
1150 *----------------------------------------------------------------------
1152 * Tk_GetFontFromObj --
1154 * Find the font that corresponds to a given object. The font must
1155 * have already been created by Tk_GetFont or Tk_AllocFontFromObj.
1158 * The return value is a token for the font that matches objPtr
1159 * and is suitable for use in tkwin.
1162 * If the object is not already a font ref, the conversion will free
1163 * any old internal representation.
1165 *----------------------------------------------------------------------
1169 Tk_GetFontFromObj(tkwin, objPtr)
1170 Tk_Window tkwin; /* The window that the font will be used in. */
1171 Tcl_Obj *objPtr; /* The object from which to get the font. */
1173 TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
1175 Tcl_HashEntry *hashPtr;
1177 if (objPtr->typePtr != &tkFontObjType) {
1178 SetFontFromAny((Tcl_Interp *) NULL, objPtr);
1181 fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
1183 if (fontPtr != NULL) {
1184 if (fontPtr->resourceRefCount == 0) {
1186 * This is a stale reference: it refers to a TkFont that's
1187 * no longer in use. Clear the reference.
1190 FreeFontObjProc(objPtr);
1192 } else if (Tk_Screen(tkwin) == fontPtr->screen) {
1193 return (Tk_Font) fontPtr;
1198 * Next, search the list of fonts that have the name we want, to see
1199 * if one of them is for the right screen.
1202 if (fontPtr != NULL) {
1203 hashPtr = fontPtr->cacheHashPtr;
1204 FreeFontObjProc(objPtr);
1206 hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr));
1208 if (hashPtr != NULL) {
1209 for (fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); fontPtr != NULL;
1210 fontPtr = fontPtr->nextPtr) {
1211 if (Tk_Screen(tkwin) == fontPtr->screen) {
1212 fontPtr->objRefCount++;
1213 objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
1214 return (Tk_Font) fontPtr;
1219 panic("Tk_GetFontFromObj called with non-existent font!");
1224 *----------------------------------------------------------------------
1228 * Convert the internal representation of a Tcl object to the
1229 * font internal form.
1232 * Always returns TCL_OK.
1235 * The object is left with its typePtr pointing to tkFontObjType.
1236 * The TkFont pointer is NULL.
1238 *----------------------------------------------------------------------
1242 SetFontFromAny(interp, objPtr)
1243 Tcl_Interp *interp; /* Used for error reporting if not NULL. */
1244 Tcl_Obj *objPtr; /* The object to convert. */
1246 Tcl_ObjType *typePtr;
1249 * Free the old internalRep before setting the new one.
1252 Tcl_GetString(objPtr);
1253 typePtr = objPtr->typePtr;
1254 if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
1255 (*typePtr->freeIntRepProc)(objPtr);
1257 objPtr->typePtr = &tkFontObjType;
1258 objPtr->internalRep.twoPtrValue.ptr1 = NULL;
1264 *---------------------------------------------------------------------------
1268 * Given a font, return a textual string identifying it.
1271 * The return value is the description that was passed to
1272 * Tk_GetFont() to create the font. The storage for the returned
1273 * string is only guaranteed to persist until the font is deleted.
1274 * The caller should not modify this string.
1279 *---------------------------------------------------------------------------
1283 Tk_NameOfFont(tkfont)
1284 Tk_Font tkfont; /* Font whose name is desired. */
1288 fontPtr = (TkFont *) tkfont;
1289 return fontPtr->cacheHashPtr->key.string;
1293 *---------------------------------------------------------------------------
1297 * Called to release a font allocated by Tk_GetFont().
1303 * The reference count associated with font is decremented, and
1304 * only deallocated when no one is using it.
1306 *---------------------------------------------------------------------------
1311 Tk_Font tkfont; /* Font to be released. */
1313 TkFont *fontPtr, *prevPtr;
1316 if (tkfont == NULL) {
1319 fontPtr = (TkFont *) tkfont;
1320 fontPtr->resourceRefCount--;
1321 if (fontPtr->resourceRefCount > 0) {
1324 if (fontPtr->namedHashPtr != NULL) {
1326 * This font derived from a named font. Reduce the reference
1327 * count on the named font and free it if no-one else is
1331 nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr);
1333 if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) {
1334 Tcl_DeleteHashEntry(fontPtr->namedHashPtr);
1335 ckfree((char *) nfPtr);
1339 prevPtr = (TkFont *) Tcl_GetHashValue(fontPtr->cacheHashPtr);
1340 if (prevPtr == fontPtr) {
1341 if (fontPtr->nextPtr == NULL) {
1342 Tcl_DeleteHashEntry(fontPtr->cacheHashPtr);
1344 Tcl_SetHashValue(fontPtr->cacheHashPtr, fontPtr->nextPtr);
1347 while (prevPtr->nextPtr != fontPtr) {
1348 prevPtr = prevPtr->nextPtr;
1350 prevPtr->nextPtr = fontPtr->nextPtr;
1353 TkpDeleteFont(fontPtr);
1354 if (fontPtr->objRefCount == 0) {
1355 ckfree((char *) fontPtr);
1360 *---------------------------------------------------------------------------
1362 * Tk_FreeFontFromObj --
1364 * Called to release a font inside a Tcl_Obj *. Decrements the refCount
1365 * of the font and removes it from the hash tables if necessary.
1371 * The reference count associated with font is decremented, and
1372 * only deallocated when no one is using it.
1374 *---------------------------------------------------------------------------
1378 Tk_FreeFontFromObj(tkwin, objPtr)
1379 Tk_Window tkwin; /* The window this font lives in. Needed
1380 * for the screen value. */
1381 Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */
1383 Tk_FreeFont(Tk_GetFontFromObj(tkwin, objPtr));
1387 *---------------------------------------------------------------------------
1389 * FreeFontObjProc --
1391 * This proc is called to release an object reference to a font.
1392 * Called when the object's internal rep is released or when
1393 * the cached fontPtr needs to be changed.
1399 * The object reference count is decremented. When both it
1400 * and the hash ref count go to zero, the font's resources
1403 *---------------------------------------------------------------------------
1407 FreeFontObjProc(objPtr)
1408 Tcl_Obj *objPtr; /* The object we are releasing. */
1410 TkFont *fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
1412 if (fontPtr != NULL) {
1413 fontPtr->objRefCount--;
1414 if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) {
1415 ckfree((char *) fontPtr);
1416 objPtr->internalRep.twoPtrValue.ptr1 = NULL;
1422 *---------------------------------------------------------------------------
1426 * When a cached font object is duplicated, this is called to
1427 * update the internal reps.
1433 * The font's objRefCount is incremented and the internal rep
1434 * of the copy is set to point to it.
1436 *---------------------------------------------------------------------------
1440 DupFontObjProc(srcObjPtr, dupObjPtr)
1441 Tcl_Obj *srcObjPtr; /* The object we are copying from. */
1442 Tcl_Obj *dupObjPtr; /* The object we are copying to. */
1444 TkFont *fontPtr = (TkFont *) srcObjPtr->internalRep.twoPtrValue.ptr1;
1446 dupObjPtr->typePtr = srcObjPtr->typePtr;
1447 dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
1449 if (fontPtr != NULL) {
1450 fontPtr->objRefCount++;
1455 *---------------------------------------------------------------------------
1459 * Given a font, return an opaque handle that should be selected
1460 * into the XGCValues structure in order to get the constructed
1461 * gc to use this font. This procedure would go away if the
1462 * XGCValues structure were replaced with a TkGCValues structure.
1470 *---------------------------------------------------------------------------
1475 Tk_Font tkfont; /* Font that is going to be selected into GC. */
1479 fontPtr = (TkFont *) tkfont;
1480 return fontPtr->fid;
1484 *---------------------------------------------------------------------------
1486 * Tk_GetFontMetrics --
1488 * Returns overall ascent and descent metrics for the given font.
1489 * These values can be used to space multiple lines of text and
1490 * to align the baselines of text in different fonts.
1493 * If *heightPtr is non-NULL, it is filled with the overall height
1494 * of the font, which is the sum of the ascent and descent.
1495 * If *ascentPtr or *descentPtr is non-NULL, they are filled with
1496 * the ascent and/or descent information for the font.
1501 *---------------------------------------------------------------------------
1504 Tk_GetFontMetrics(tkfont, fmPtr)
1505 Tk_Font tkfont; /* Font in which metrics are calculated. */
1506 Tk_FontMetrics *fmPtr; /* Pointer to structure in which font
1507 * metrics for tkfont will be stored. */
1511 fontPtr = (TkFont *) tkfont;
1512 fmPtr->ascent = fontPtr->fm.ascent;
1513 fmPtr->descent = fontPtr->fm.descent;
1514 fmPtr->linespace = fontPtr->fm.ascent + fontPtr->fm.descent;
1518 *---------------------------------------------------------------------------
1520 * Tk_PostscriptFontName --
1522 * Given a Tk_Font, return the name of the corresponding Postscript
1526 * The return value is the pointsize of the given Tk_Font.
1527 * The name of the Postscript font is appended to dsPtr.
1530 * If the font does not exist on the printer, the print job will
1531 * fail at print time. Given a "reasonable" Postscript printer,
1532 * the following Tk_Font font families should print correctly:
1534 * Avant Garde, Arial, Bookman, Courier, Courier New, Geneva,
1535 * Helvetica, Monaco, New Century Schoolbook, New York,
1536 * Palatino, Symbol, Times, Times New Roman, Zapf Chancery,
1537 * and Zapf Dingbats.
1539 * Any other Tk_Font font families may not print correctly
1540 * because the computed Postscript font name may be incorrect.
1542 *---------------------------------------------------------------------------
1546 Tk_PostscriptFontName(tkfont, dsPtr)
1547 Tk_Font tkfont; /* Font in which text will be printed. */
1548 Tcl_DString *dsPtr; /* Pointer to an initialized Tcl_DString to
1549 * which the name of the Postscript font that
1550 * corresponds to tkfont will be appended. */
1553 Tk_Uid family, weightString, slantString;
1557 len = Tcl_DStringLength(dsPtr);
1558 fontPtr = (TkFont *) tkfont;
1561 * Convert the case-insensitive Tk_Font family name to the
1562 * case-sensitive Postscript family name. Take out any spaces and
1563 * capitalize the first letter of each word.
1566 family = fontPtr->fa.family;
1567 if (strncasecmp(family, "itc ", 4) == 0) {
1568 family = family + 4;
1570 if ((strcasecmp(family, "Arial") == 0)
1571 || (strcasecmp(family, "Geneva") == 0)) {
1572 family = "Helvetica";
1573 } else if ((strcasecmp(family, "Times New Roman") == 0)
1574 || (strcasecmp(family, "New York") == 0)) {
1576 } else if ((strcasecmp(family, "Courier New") == 0)
1577 || (strcasecmp(family, "Monaco") == 0)) {
1579 } else if (strcasecmp(family, "AvantGarde") == 0) {
1580 family = "AvantGarde";
1581 } else if (strcasecmp(family, "ZapfChancery") == 0) {
1582 family = "ZapfChancery";
1583 } else if (strcasecmp(family, "ZapfDingbats") == 0) {
1584 family = "ZapfDingbats";
1589 * Inline, capitalize the first letter of each word, lowercase the
1590 * rest of the letters in each word, and then take out the spaces
1591 * between the words. This may make the DString shorter, which is
1595 Tcl_DStringAppend(dsPtr, family, -1);
1597 src = dest = Tcl_DStringValue(dsPtr) + len;
1599 for (; *src != '\0'; ) {
1600 while (isspace(UCHAR(*src))) { /* INTL: ISO space */
1604 src += Tcl_UtfToUniChar(src, &ch);
1606 ch = Tcl_UniCharToUpper(ch);
1609 ch = Tcl_UniCharToLower(ch);
1611 dest += Tcl_UniCharToUtf(ch, dest);
1614 Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr));
1615 family = Tcl_DStringValue(dsPtr) + len;
1617 if (family != Tcl_DStringValue(dsPtr) + len) {
1618 Tcl_DStringAppend(dsPtr, family, -1);
1619 family = Tcl_DStringValue(dsPtr) + len;
1622 if (strcasecmp(family, "NewCenturySchoolbook") == 0) {
1623 Tcl_DStringSetLength(dsPtr, len);
1624 Tcl_DStringAppend(dsPtr, "NewCenturySchlbk", -1);
1625 family = Tcl_DStringValue(dsPtr) + len;
1629 * Get the string to use for the weight.
1632 weightString = NULL;
1633 if (fontPtr->fa.weight == TK_FW_NORMAL) {
1634 if (strcmp(family, "Bookman") == 0) {
1635 weightString = "Light";
1636 } else if (strcmp(family, "AvantGarde") == 0) {
1637 weightString = "Book";
1638 } else if (strcmp(family, "ZapfChancery") == 0) {
1639 weightString = "Medium";
1642 if ((strcmp(family, "Bookman") == 0)
1643 || (strcmp(family, "AvantGarde") == 0)) {
1644 weightString = "Demi";
1646 weightString = "Bold";
1651 * Get the string to use for the slant.
1655 if (fontPtr->fa.slant == TK_FS_ROMAN) {
1658 if ((strcmp(family, "Helvetica") == 0)
1659 || (strcmp(family, "Courier") == 0)
1660 || (strcmp(family, "AvantGarde") == 0)) {
1661 slantString = "Oblique";
1663 slantString = "Italic";
1668 * The string "Roman" needs to be added to some fonts that are not bold
1672 if ((slantString == NULL) && (weightString == NULL)) {
1673 if ((strcmp(family, "Times") == 0)
1674 || (strcmp(family, "NewCenturySchlbk") == 0)
1675 || (strcmp(family, "Palatino") == 0)) {
1676 Tcl_DStringAppend(dsPtr, "-Roman", -1);
1679 Tcl_DStringAppend(dsPtr, "-", -1);
1680 if (weightString != NULL) {
1681 Tcl_DStringAppend(dsPtr, weightString, -1);
1683 if (slantString != NULL) {
1684 Tcl_DStringAppend(dsPtr, slantString, -1);
1688 return fontPtr->fa.size;
1692 *---------------------------------------------------------------------------
1696 * A wrapper function for the more complicated interface of
1697 * Tk_MeasureChars. Computes how much space the given
1698 * simple string needs.
1701 * The return value is the width (in pixels) of the given string.
1706 *---------------------------------------------------------------------------
1710 Tk_TextWidth(tkfont, string, numBytes)
1711 Tk_Font tkfont; /* Font in which text will be measured. */
1712 CONST char *string; /* String whose width will be computed. */
1713 int numBytes; /* Number of bytes to consider from
1714 * string, or < 0 for strlen(). */
1719 numBytes = strlen(string);
1721 Tk_MeasureChars(tkfont, string, numBytes, -1, 0, &width);
1726 *---------------------------------------------------------------------------
1728 * Tk_UnderlineChars --
1730 * This procedure draws an underline for a given range of characters
1731 * in a given string. It doesn't draw the characters (which are
1732 * assumed to have been displayed previously); it just draws the
1733 * underline. This procedure would mainly be used to quickly
1734 * underline a few characters without having to construct an
1735 * underlined font. To produce properly underlined text, the
1736 * appropriate underlined font should be constructed and used.
1742 * Information gets displayed in "drawable".
1744 *----------------------------------------------------------------------
1748 Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstByte,
1750 Display *display; /* Display on which to draw. */
1751 Drawable drawable; /* Window or pixmap in which to draw. */
1752 GC gc; /* Graphics context for actually drawing
1754 Tk_Font tkfont; /* Font used in GC; must have been allocated
1755 * by Tk_GetFont(). Used for character
1756 * dimensions, etc. */
1757 CONST char *string; /* String containing characters to be
1758 * underlined or overstruck. */
1759 int x, y; /* Coordinates at which first character of
1760 * string is drawn. */
1761 int firstByte; /* Index of first byte of first character. */
1762 int lastByte; /* Index of first byte after the last
1768 fontPtr = (TkFont *) tkfont;
1770 Tk_MeasureChars(tkfont, string, firstByte, -1, 0, &startX);
1771 Tk_MeasureChars(tkfont, string, lastByte, -1, 0, &endX);
1773 XFillRectangle(display, drawable, gc, x + startX,
1774 y + fontPtr->underlinePos, (unsigned int) (endX - startX),
1775 (unsigned int) fontPtr->underlineHeight);
1779 *---------------------------------------------------------------------------
1781 * Tk_ComputeTextLayout --
1783 * Computes the amount of screen space needed to display a
1784 * multi-line, justified string of text. Records all the
1785 * measurements that were done to determine to size and
1786 * positioning of the individual lines of text; this information
1787 * can be used by the Tk_DrawTextLayout() procedure to
1788 * display the text quickly (without remeasuring it).
1790 * This procedure is useful for simple widgets that want to
1791 * display single-font, multi-line text and want Tk to handle the
1795 * The return value is a Tk_TextLayout token that holds the
1796 * measurement information for the given string. The token is
1797 * only valid for the given string. If the string is freed,
1798 * the token is no longer valid and must also be freed. To free
1799 * the token, call Tk_FreeTextLayout().
1801 * The dimensions of the screen area needed to display the text
1802 * are stored in *widthPtr and *heightPtr.
1805 * Memory is allocated to hold the measurement information.
1807 *---------------------------------------------------------------------------
1811 Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags,
1812 widthPtr, heightPtr)
1813 Tk_Font tkfont; /* Font that will be used to display text. */
1814 CONST char *string; /* String whose dimensions are to be
1816 int numChars; /* Number of characters to consider from
1817 * string, or < 0 for strlen(). */
1818 int wrapLength; /* Longest permissible line length, in
1819 * pixels. <= 0 means no automatic wrapping:
1820 * just let lines get as long as needed. */
1821 Tk_Justify justify; /* How to justify lines. */
1822 int flags; /* Flag bits OR-ed together.
1823 * TK_IGNORE_TABS means that tab characters
1824 * should not be expanded. TK_IGNORE_NEWLINES
1825 * means that newline characters should not
1826 * cause a line break. */
1827 int *widthPtr; /* Filled with width of string. */
1828 int *heightPtr; /* Filled with height of string. */
1831 CONST char *start, *end, *special;
1832 int n, y, bytesThisChunk, maxChunks;
1833 int baseline, height, curX, newX, maxWidth;
1834 TextLayout *layoutPtr;
1835 LayoutChunk *chunkPtr;
1836 CONST TkFontMetrics *fmPtr;
1837 Tcl_DString lineBuffer;
1839 int curLine, layoutHeight;
1841 Tcl_DStringInit(&lineBuffer);
1843 fontPtr = (TkFont *) tkfont;
1844 if ((fontPtr == NULL) || (string == NULL)) {
1845 if (widthPtr != NULL) {
1848 if (heightPtr != NULL) {
1854 fmPtr = &fontPtr->fm;
1856 height = fmPtr->ascent + fmPtr->descent;
1859 numChars = Tcl_NumUtfChars(string, -1);
1861 if (wrapLength == 0) {
1867 layoutPtr = (TextLayout *) ckalloc(sizeof(TextLayout)
1868 + (maxChunks - 1) * sizeof(LayoutChunk));
1869 layoutPtr->tkfont = tkfont;
1870 layoutPtr->string = string;
1871 layoutPtr->numChunks = 0;
1873 baseline = fmPtr->ascent;
1877 * Divide the string up into simple strings and measure each string.
1882 end = Tcl_UtfAtIndex(string, numChars);
1885 flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES;
1886 flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE;
1887 for (start = string; start < end; ) {
1888 if (start >= special) {
1890 * Find the next special character in the string.
1892 * INTL: Note that it is safe to increment by byte, because we are
1893 * looking for 7-bit characters that will appear unchanged in
1894 * UTF-8. At some point we may need to support the full Unicode
1898 for (special = start; special < end; special++) {
1899 if (!(flags & TK_IGNORE_NEWLINES)) {
1900 if ((*special == '\n') || (*special == '\r')) {
1904 if (!(flags & TK_IGNORE_TABS)) {
1905 if (*special == '\t') {
1913 * Special points at the next special character (or the end of the
1914 * string). Process characters between start and special.
1918 if (start < special) {
1919 bytesThisChunk = Tk_MeasureChars(tkfont, start, special - start,
1920 wrapLength - curX, flags, &newX);
1922 flags &= ~TK_AT_LEAST_ONE;
1923 if (bytesThisChunk > 0) {
1924 chunkPtr = NewChunk(&layoutPtr, &maxChunks, start,
1925 bytesThisChunk, curX, newX, baseline);
1927 start += bytesThisChunk;
1932 if ((start == special) && (special < end)) {
1934 * Handle the special character.
1936 * INTL: Special will be pointing at a 7-bit character so we
1937 * can safely treat it as a single byte.
1941 if (*special == '\t') {
1942 newX = curX + fontPtr->tabWidth;
1943 newX -= newX % fontPtr->tabWidth;
1944 NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX,
1945 baseline)->numDisplayChars = -1;
1947 if ((start < end) &&
1948 ((wrapLength <= 0) || (newX <= wrapLength))) {
1950 * More chars can still fit on this line.
1954 flags &= ~TK_AT_LEAST_ONE;
1958 NewChunk(&layoutPtr, &maxChunks, start, 1, curX, curX,
1959 baseline)->numDisplayChars = -1;
1966 * No more characters are going to go on this line, either because
1967 * no more characters can fit or there are no more characters left.
1968 * Consume all extra spaces at end of line.
1971 while ((start < end) && isspace(UCHAR(*start))) { /* INTL: ISO space */
1972 if (!(flags & TK_IGNORE_NEWLINES)) {
1973 if ((*start == '\n') || (*start == '\r')) {
1977 if (!(flags & TK_IGNORE_TABS)) {
1978 if (*start == '\t') {
1984 if (chunkPtr != NULL) {
1988 * Append all the extra spaces on this line to the end of the
1989 * last text chunk. This is a little tricky because we are
1990 * switching back and forth between characters and bytes.
1993 end = chunkPtr->start + chunkPtr->numBytes;
1994 bytesThisChunk = start - end;
1995 if (bytesThisChunk > 0) {
1996 bytesThisChunk = Tk_MeasureChars(tkfont, end, bytesThisChunk,
1997 -1, 0, &chunkPtr->totalWidth);
1998 chunkPtr->numBytes += bytesThisChunk;
1999 chunkPtr->numChars += Tcl_NumUtfChars(end, bytesThisChunk);
2000 chunkPtr->totalWidth += curX;
2005 flags |= TK_AT_LEAST_ONE;
2008 * Save current line length, then move current position to start of
2012 if (curX > maxWidth) {
2017 * Remember width of this line, so that all chunks on this line
2018 * can be centered or right justified, if necessary.
2021 Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));
2028 * If last line ends with a newline, then we need to make a 0 width
2029 * chunk on the next line. Otherwise "Hello" and "Hello\n" are the
2033 if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) {
2034 if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == '\n') {
2035 chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX,
2037 chunkPtr->numDisplayChars = -1;
2038 Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));
2043 layoutPtr->width = maxWidth;
2044 layoutHeight = baseline - fmPtr->ascent;
2045 if (layoutPtr->numChunks == 0) {
2046 layoutHeight = height;
2049 * This fake chunk is used by the other procedures so that they can
2050 * pretend that there is a chunk with no chars in it, which makes
2051 * the coding simpler.
2054 layoutPtr->numChunks = 1;
2055 layoutPtr->chunks[0].start = string;
2056 layoutPtr->chunks[0].numBytes = 0;
2057 layoutPtr->chunks[0].numChars = 0;
2058 layoutPtr->chunks[0].numDisplayChars = -1;
2059 layoutPtr->chunks[0].x = 0;
2060 layoutPtr->chunks[0].y = fmPtr->ascent;
2061 layoutPtr->chunks[0].totalWidth = 0;
2062 layoutPtr->chunks[0].displayWidth = 0;
2065 * Using maximum line length, shift all the chunks so that the lines
2066 * are all justified correctly.
2070 chunkPtr = layoutPtr->chunks;
2072 lineLengths = (int *) Tcl_DStringValue(&lineBuffer);
2073 for (n = 0; n < layoutPtr->numChunks; n++) {
2076 if (chunkPtr->y != y) {
2080 extra = maxWidth - lineLengths[curLine];
2081 if (justify == TK_JUSTIFY_CENTER) {
2082 chunkPtr->x += extra / 2;
2083 } else if (justify == TK_JUSTIFY_RIGHT) {
2084 chunkPtr->x += extra;
2090 if (widthPtr != NULL) {
2091 *widthPtr = layoutPtr->width;
2093 if (heightPtr != NULL) {
2094 *heightPtr = layoutHeight;
2096 Tcl_DStringFree(&lineBuffer);
2098 return (Tk_TextLayout) layoutPtr;
2102 *---------------------------------------------------------------------------
2104 * Tk_FreeTextLayout --
2106 * This procedure is called to release the storage associated with
2107 * a Tk_TextLayout when it is no longer needed.
2115 *---------------------------------------------------------------------------
2119 Tk_FreeTextLayout(textLayout)
2120 Tk_TextLayout textLayout; /* The text layout to be released. */
2122 TextLayout *layoutPtr;
2124 layoutPtr = (TextLayout *) textLayout;
2125 if (layoutPtr != NULL) {
2126 ckfree((char *) layoutPtr);
2131 *---------------------------------------------------------------------------
2133 * Tk_DrawTextLayout --
2135 * Use the information in the Tk_TextLayout token to display a
2136 * multi-line, justified string of text.
2138 * This procedure is useful for simple widgets that need to
2139 * display single-font, multi-line text and want Tk to handle
2146 * Text drawn on the screen.
2148 *---------------------------------------------------------------------------
2152 Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar)
2153 Display *display; /* Display on which to draw. */
2154 Drawable drawable; /* Window or pixmap in which to draw. */
2155 GC gc; /* Graphics context to use for drawing text. */
2156 Tk_TextLayout layout; /* Layout information, from a previous call
2157 * to Tk_ComputeTextLayout(). */
2158 int x, y; /* Upper-left hand corner of rectangle in
2159 * which to draw (pixels). */
2160 int firstChar; /* The index of the first character to draw
2161 * from the given text item. 0 specfies the
2163 int lastChar; /* The index just after the last character
2164 * to draw from the given text item. A number
2165 * < 0 means to draw all characters. */
2167 TextLayout *layoutPtr;
2168 int i, numDisplayChars, drawX;
2169 CONST char *firstByte;
2170 CONST char *lastByte;
2171 LayoutChunk *chunkPtr;
2173 layoutPtr = (TextLayout *) layout;
2174 if (layoutPtr == NULL) {
2179 lastChar = 100000000;
2181 chunkPtr = layoutPtr->chunks;
2182 for (i = 0; i < layoutPtr->numChunks; i++) {
2183 numDisplayChars = chunkPtr->numDisplayChars;
2184 if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) {
2185 if (firstChar <= 0) {
2188 firstByte = chunkPtr->start;
2190 firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar);
2191 Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start,
2192 firstByte - chunkPtr->start, -1, 0, &drawX);
2194 if (lastChar < numDisplayChars) {
2195 numDisplayChars = lastChar;
2197 lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars);
2198 Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont,
2199 firstByte, lastByte - firstByte,
2200 x + chunkPtr->x + drawX, y + chunkPtr->y);
2202 firstChar -= chunkPtr->numChars;
2203 lastChar -= chunkPtr->numChars;
2204 if (lastChar <= 0) {
2212 *---------------------------------------------------------------------------
2214 * Tk_UnderlineTextLayout --
2216 * Use the information in the Tk_TextLayout token to display an
2217 * underline below an individual character. This procedure does
2218 * not draw the text, just the underline.
2220 * This procedure is useful for simple widgets that need to
2221 * display single-font, multi-line text with an individual
2222 * character underlined and want Tk to handle the details.
2223 * To display larger amounts of underlined text, construct
2224 * and use an underlined font.
2230 * Underline drawn on the screen.
2232 *---------------------------------------------------------------------------
2236 Tk_UnderlineTextLayout(display, drawable, gc, layout, x, y, underline)
2237 Display *display; /* Display on which to draw. */
2238 Drawable drawable; /* Window or pixmap in which to draw. */
2239 GC gc; /* Graphics context to use for drawing text. */
2240 Tk_TextLayout layout; /* Layout information, from a previous call
2241 * to Tk_ComputeTextLayout(). */
2242 int x, y; /* Upper-left hand corner of rectangle in
2243 * which to draw (pixels). */
2244 int underline; /* Index of the single character to
2245 * underline, or -1 for no underline. */
2247 TextLayout *layoutPtr;
2249 int xx, yy, width, height;
2251 if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0)
2253 layoutPtr = (TextLayout *) layout;
2254 fontPtr = (TkFont *) layoutPtr->tkfont;
2256 XFillRectangle(display, drawable, gc, x + xx,
2257 y + yy + fontPtr->fm.ascent + fontPtr->underlinePos,
2258 (unsigned int) width, (unsigned int) fontPtr->underlineHeight);
2263 *---------------------------------------------------------------------------
2267 * Use the information in the Tk_TextLayout token to determine the
2268 * character closest to the given point. The point must be
2269 * specified with respect to the upper-left hand corner of the
2270 * text layout, which is considered to be located at (0, 0).
2272 * Any point whose y-value is less that 0 will be considered closest
2273 * to the first character in the text layout; any point whose y-value
2274 * is greater than the height of the text layout will be considered
2275 * closest to the last character in the text layout.
2277 * Any point whose x-value is less than 0 will be considered closest
2278 * to the first character on that line; any point whose x-value is
2279 * greater than the width of the text layout will be considered
2280 * closest to the last character on that line.
2283 * The return value is the index of the character that was
2284 * closest to the point. Given a text layout with no characters,
2285 * the value 0 will always be returned, referring to a hypothetical
2286 * zero-width placeholder character.
2291 *---------------------------------------------------------------------------
2295 Tk_PointToChar(layout, x, y)
2296 Tk_TextLayout layout; /* Layout information, from a previous call
2297 * to Tk_ComputeTextLayout(). */
2298 int x, y; /* Coordinates of point to check, with
2299 * respect to the upper-left corner of the
2302 TextLayout *layoutPtr;
2303 LayoutChunk *chunkPtr, *lastPtr;
2305 int i, n, dummy, baseline, pos, numChars;
2309 * Point lies above any line in this layout. Return the index of
2317 * Find which line contains the point.
2320 layoutPtr = (TextLayout *) layout;
2321 fontPtr = (TkFont *) layoutPtr->tkfont;
2322 lastPtr = chunkPtr = layoutPtr->chunks;
2324 for (i = 0; i < layoutPtr->numChunks; i++) {
2325 baseline = chunkPtr->y;
2326 if (y < baseline + fontPtr->fm.descent) {
2327 if (x < chunkPtr->x) {
2329 * Point is to the left of all chunks on this line. Return
2330 * the index of the first character on this line.
2335 if (x >= layoutPtr->width) {
2337 * If point lies off right side of the text layout, return
2338 * the last char in the last chunk on this line. Without
2339 * this, it might return the index of the first char that
2340 * was located outside of the text layout.
2347 * Examine all chunks on this line to see which one contains
2348 * the specified point.
2352 while ((i < layoutPtr->numChunks) && (chunkPtr->y == baseline)) {
2353 if (x < chunkPtr->x + chunkPtr->totalWidth) {
2355 * Point falls on one of the characters in this chunk.
2358 if (chunkPtr->numDisplayChars < 0) {
2360 * This is a special chunk that encapsulates a single
2361 * tab or newline char.
2366 n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start,
2367 chunkPtr->numBytes, x - chunkPtr->x,
2369 return numChars + Tcl_NumUtfChars(chunkPtr->start, n);
2371 numChars += chunkPtr->numChars;
2378 * Point is to the right of all chars in all the chunks on this
2379 * line. Return the index just past the last char in the last
2380 * chunk on this line.
2384 if (i < layoutPtr->numChunks) {
2389 numChars += chunkPtr->numChars;
2395 * Point lies below any line in this text layout. Return the index
2396 * just past the last char.
2399 return (lastPtr->start + lastPtr->numChars) - layoutPtr->string;
2403 *---------------------------------------------------------------------------
2407 * Use the information in the Tk_TextLayout token to return the
2408 * bounding box for the character specified by index.
2410 * The width of the bounding box is the advance width of the
2411 * character, and does not include and left- or right-bearing.
2412 * Any character that extends partially outside of the
2413 * text layout is considered to be truncated at the edge. Any
2414 * character which is located completely outside of the text
2415 * layout is considered to be zero-width and pegged against
2418 * The height of the bounding box is the line height for this font,
2419 * extending from the top of the ascent to the bottom of the
2420 * descent. Information about the actual height of the individual
2421 * letter is not available.
2423 * A text layout that contains no characters is considered to
2424 * contain a single zero-width placeholder character.
2427 * The return value is 0 if the index did not specify a character
2428 * in the text layout, or non-zero otherwise. In that case,
2429 * *bbox is filled with the bounding box of the character.
2434 *---------------------------------------------------------------------------
2438 Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr)
2439 Tk_TextLayout layout; /* Layout information, from a previous call to
2440 * Tk_ComputeTextLayout(). */
2441 int index; /* The index of the character whose bbox is
2443 int *xPtr, *yPtr; /* Filled with the upper-left hand corner, in
2444 * pixels, of the bounding box for the character
2445 * specified by index, if non-NULL. */
2446 int *widthPtr, *heightPtr;
2447 /* Filled with the width and height of the
2448 * bounding box for the character specified by
2449 * index, if non-NULL. */
2451 TextLayout *layoutPtr;
2452 LayoutChunk *chunkPtr;
2462 layoutPtr = (TextLayout *) layout;
2463 chunkPtr = layoutPtr->chunks;
2464 tkfont = layoutPtr->tkfont;
2465 fontPtr = (TkFont *) tkfont;
2467 for (i = 0; i < layoutPtr->numChunks; i++) {
2468 if (chunkPtr->numDisplayChars < 0) {
2471 w = chunkPtr->totalWidth;
2474 } else if (index < chunkPtr->numChars) {
2475 end = Tcl_UtfAtIndex(chunkPtr->start, index);
2477 Tk_MeasureChars(tkfont, chunkPtr->start,
2478 end - chunkPtr->start, -1, 0, &x);
2481 if (widthPtr != NULL) {
2482 Tk_MeasureChars(tkfont, end, Tcl_UtfNext(end) - end,
2487 index -= chunkPtr->numChars;
2492 * Special case to get location just past last char in layout.
2496 x = chunkPtr->x + chunkPtr->totalWidth;
2503 * Ensure that the bbox lies within the text layout. This forces all
2504 * chars that extend off the right edge of the text layout to have
2505 * truncated widths, and all chars that are completely off the right
2506 * edge of the text layout to peg to the edge and have 0 width.
2510 *yPtr = chunkPtr->y - fontPtr->fm.ascent;
2512 if (heightPtr != NULL) {
2513 *heightPtr = fontPtr->fm.ascent + fontPtr->fm.descent;
2516 if (x > layoutPtr->width) {
2517 x = layoutPtr->width;
2522 if (widthPtr != NULL) {
2523 if (x + w > layoutPtr->width) {
2524 w = layoutPtr->width - x;
2533 *---------------------------------------------------------------------------
2535 * Tk_DistanceToTextLayout --
2537 * Computes the distance in pixels from the given point to the
2538 * given text layout. Non-displaying space characters that occur
2539 * at the end of individual lines in the text layout are ignored
2540 * for hit detection purposes.
2543 * The return value is 0 if the point (x, y) is inside the text
2544 * layout. If the point isn't inside the text layout then the
2545 * return value is the distance in pixels from the point to the
2551 *---------------------------------------------------------------------------
2555 Tk_DistanceToTextLayout(layout, x, y)
2556 Tk_TextLayout layout; /* Layout information, from a previous call
2557 * to Tk_ComputeTextLayout(). */
2558 int x, y; /* Coordinates of point to check, with
2559 * respect to the upper-left corner of the
2560 * text layout (in pixels). */
2562 int i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent;
2563 LayoutChunk *chunkPtr;
2564 TextLayout *layoutPtr;
2567 layoutPtr = (TextLayout *) layout;
2568 fontPtr = (TkFont *) layoutPtr->tkfont;
2569 ascent = fontPtr->fm.ascent;
2570 descent = fontPtr->fm.descent;
2573 chunkPtr = layoutPtr->chunks;
2574 for (i = 0; i < layoutPtr->numChunks; i++) {
2575 if (chunkPtr->start[0] == '\n') {
2577 * Newline characters are not counted when computing distance
2578 * (but tab characters would still be considered).
2586 y1 = chunkPtr->y - ascent;
2587 x2 = chunkPtr->x + chunkPtr->displayWidth;
2588 y2 = chunkPtr->y + descent;
2592 } else if (x >= x2) {
2600 } else if (y >= y2) {
2605 if ((xDiff == 0) && (yDiff == 0)) {
2608 dist = (int) hypot((double) xDiff, (double) yDiff);
2609 if ((dist < minDist) || (minDist == 0)) {
2618 *---------------------------------------------------------------------------
2620 * Tk_IntersectTextLayout --
2622 * Determines whether a text layout lies entirely inside,
2623 * entirely outside, or overlaps a given rectangle. Non-displaying
2624 * space characters that occur at the end of individual lines in
2625 * the text layout are ignored for intersection calculations.
2628 * The return value is -1 if the text layout is entirely outside of
2629 * the rectangle, 0 if it overlaps, and 1 if it is entirely inside
2635 *---------------------------------------------------------------------------
2639 Tk_IntersectTextLayout(layout, x, y, width, height)
2640 Tk_TextLayout layout; /* Layout information, from a previous call
2641 * to Tk_ComputeTextLayout(). */
2642 int x, y; /* Upper-left hand corner, in pixels, of
2643 * rectangular area to compare with text
2644 * layout. Coordinates are with respect to
2645 * the upper-left hand corner of the text
2647 int width, height; /* The width and height of the above
2648 * rectangular area, in pixels. */
2650 int result, i, x1, y1, x2, y2;
2651 TextLayout *layoutPtr;
2652 LayoutChunk *chunkPtr;
2654 int left, top, right, bottom;
2657 * Scan the chunks one at a time, seeing whether each is entirely in,
2658 * entirely out, or overlapping the rectangle. If an overlap is
2659 * detected, return immediately; otherwise wait until all chunks have
2660 * been processed and see if they were all inside or all outside.
2663 layoutPtr = (TextLayout *) layout;
2664 chunkPtr = layoutPtr->chunks;
2665 fontPtr = (TkFont *) layoutPtr->tkfont;
2670 bottom = y + height;
2673 for (i = 0; i < layoutPtr->numChunks; i++) {
2674 if (chunkPtr->start[0] == '\n') {
2676 * Newline characters are not counted when computing area
2677 * intersection (but tab characters would still be considered).
2685 y1 = chunkPtr->y - fontPtr->fm.ascent;
2686 x2 = chunkPtr->x + chunkPtr->displayWidth;
2687 y2 = chunkPtr->y + fontPtr->fm.descent;
2689 if ((right < x1) || (left >= x2)
2690 || (bottom < y1) || (top >= y2)) {
2695 } else if ((x1 < left) || (x2 >= right)
2696 || (y1 < top) || (y2 >= bottom)) {
2698 } else if (result == -1) {
2709 *---------------------------------------------------------------------------
2711 * Tk_TextLayoutToPostscript --
2713 * Outputs the contents of a text layout in Postscript format.
2714 * The set of lines in the text layout will be rendered by the user
2715 * supplied Postscript function. The function should be of the form:
2717 * justify x y string function --
2719 * Justify is -1, 0, or 1, depending on whether the following string
2720 * should be left, center, or right justified, x and y is the
2721 * location for the origin of the string, string is the sequence
2722 * of characters to be printed, and function is the name of the
2723 * caller-provided function; the function should leave nothing
2726 * The meaning of the origin of the string (x and y) depends on
2727 * the justification. For left justification, x is where the
2728 * left edge of the string should appear. For center justification,
2729 * x is where the center of the string should appear. And for right
2730 * justification, x is where the right edge of the string should
2731 * appear. This behavior is necessary because, for example, right
2732 * justified text on the screen is justified with screen metrics.
2733 * The same string needs to be justified with printer metrics on
2734 * the printer to appear in the correct place with respect to other
2735 * similarly justified strings. In all circumstances, y is the
2736 * location of the baseline for the string.
2739 * The interp's result is modified to hold the Postscript code that
2740 * will render the text layout.
2745 *---------------------------------------------------------------------------
2749 Tk_TextLayoutToPostscript(interp, layout)
2750 Tcl_Interp *interp; /* Filled with Postscript code. */
2751 Tk_TextLayout layout; /* The layout to be rendered. */
2754 char buf[MAXUSE+30];
2755 LayoutChunk *chunkPtr;
2756 int i, j, used, c, baseline;
2758 CONST char *p, *last_p,*glyphname;
2759 TextLayout *layoutPtr;
2760 char uindex[5]="\0\0\0\0";
2765 layoutPtr = (TextLayout *) layout;
2766 chunkPtr = layoutPtr->chunks;
2767 baseline = chunkPtr->y;
2771 for (i = 0; i < layoutPtr->numChunks; i++) {
2772 if (baseline != chunkPtr->y) {
2778 baseline = chunkPtr->y;
2780 if (chunkPtr->numDisplayChars <= 0) {
2781 if (chunkPtr->start[0] == '\t') {
2786 p = chunkPtr->start;
2787 for (j = 0; j < chunkPtr->numDisplayChars; j++) {
2789 * INTL: For now we just treat the characters as binary
2790 * data and display the lower byte. Eventually this should
2791 * be revised to handle international postscript fonts.
2794 p +=(charsize= Tcl_UtfToUniChar(p,&ch));
2795 Tcl_UtfToExternal(interp,NULL,last_p,charsize,0,NULL,one_char,4,
2796 NULL,&bytecount,NULL);
2797 if (bytecount == 1) {
2798 c = UCHAR(one_char[0]);
2799 /* c = UCHAR( ch & 0xFF) */;
2800 if ((c == '(') || (c == ')') || (c == '\\') || (c < 0x20)
2801 || (c >= UCHAR(0x7f))) {
2803 * Tricky point: the "03" is necessary in the sprintf
2804 * below, so that a full three digits of octal are
2805 * always generated. Without the "03", a number
2806 * following this sequence could be interpreted by
2807 * Postscript as part of this sequence.
2810 sprintf(buf + used, "\\%03o", c);
2816 /* This character doesn't belong to system character set.
2817 * So, we must use full glyph name */
2818 sprintf(uindex,"%04X",ch); /* endianness? */
2819 if ((glyphname = Tcl_GetVar2( interp , "::tk::psglyphs",uindex,0))) {
2820 if (used > 0 && buf [used-1] == '(')
2825 while( (*glyphname) && (used < (MAXUSE+27)))
2826 buf[used++] = *glyphname++ ;
2831 if (used >= MAXUSE) {
2833 Tcl_AppendResult(interp, buf, (char *) NULL);
2838 if (used >= MAXUSE) {
2840 * If there are a whole bunch of returns or tabs in a row,
2841 * then buf[] could get filled up.
2845 Tcl_AppendResult(interp, buf, (char *) NULL);
2854 Tcl_AppendResult(interp, buf, (char *) NULL);
2858 *---------------------------------------------------------------------------
2860 * ConfigAttributesObj --
2862 * Process command line options to fill in fields of a properly
2863 * initialized font attributes structure.
2866 * A standard Tcl return value. If TCL_ERROR is returned, an
2867 * error message will be left in interp's result object.
2870 * The fields of the font attributes structure get filled in with
2871 * information from argc/argv. If an error occurs while parsing,
2872 * the font attributes structure will contain all modifications
2873 * specified in the command line options up to the point of the
2876 *---------------------------------------------------------------------------
2880 ConfigAttributesObj(interp, tkwin, objc, objv, faPtr)
2881 Tcl_Interp *interp; /* Interp for error return. */
2882 Tk_Window tkwin; /* For display on which font will be used. */
2883 int objc; /* Number of elements in argv. */
2884 Tcl_Obj *CONST objv[]; /* Command line options. */
2885 TkFontAttributes *faPtr; /* Font attributes structure whose fields
2886 * are to be modified. Structure must already
2887 * be properly initialized. */
2890 Tcl_Obj *optionPtr, *valuePtr;
2893 for (i = 0; i < objc; i += 2) {
2894 optionPtr = objv[i];
2895 valuePtr = objv[i + 1];
2897 if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1,
2898 &index) != TCL_OK) {
2901 if ((i+2 >= objc) && (objc & 1)) {
2903 * This test occurs after Tcl_GetIndexFromObj() so that
2904 * "font create xyz -xyz" will return the error message
2905 * that "-xyz" is a bad option, rather than that the value
2906 * for "-xyz" is missing.
2909 Tcl_AppendResult(interp, "value for \"",
2910 Tcl_GetString(optionPtr), "\" option missing",
2917 value = Tcl_GetString(valuePtr);
2918 faPtr->family = Tk_GetUid(value);
2922 if (Tcl_GetIntFromObj(interp, valuePtr, &n) != TCL_OK) {
2929 n = TkFindStateNumObj(interp, optionPtr, weightMap, valuePtr);
2930 if (n == TK_FW_UNKNOWN) {
2937 n = TkFindStateNumObj(interp, optionPtr, slantMap, valuePtr);
2938 if (n == TK_FS_UNKNOWN) {
2944 case FONT_UNDERLINE: {
2945 if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) {
2948 faPtr->underline = n;
2951 case FONT_OVERSTRIKE: {
2952 if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) {
2955 faPtr->overstrike = n;
2964 *---------------------------------------------------------------------------
2966 * GetAttributeInfoObj --
2968 * Return information about the font attributes as a Tcl list.
2971 * The return value is TCL_OK if the objPtr was non-NULL and
2972 * specified a valid font attribute, TCL_ERROR otherwise. If TCL_OK
2973 * is returned, the interp's result object is modified to hold a
2974 * description of either the current value of a single option, or a
2975 * list of all options and their current values for the given font
2976 * attributes. If TCL_ERROR is returned, the interp's result is
2977 * set to an error message describing that the objPtr did not refer
2978 * to a valid option.
2983 *---------------------------------------------------------------------------
2987 GetAttributeInfoObj(interp, faPtr, objPtr)
2988 Tcl_Interp *interp; /* Interp to hold result. */
2989 CONST TkFontAttributes *faPtr; /* The font attributes to inspect. */
2990 Tcl_Obj *objPtr; /* If non-NULL, indicates the single
2991 * option whose value is to be
2992 * returned. Otherwise information is
2993 * returned for all options. */
2995 int i, index, start, end;
2997 Tcl_Obj *optionPtr, *valuePtr, *resultPtr;
2999 resultPtr = Tcl_GetObjResult(interp);
3002 end = FONT_NUMFIELDS;
3003 if (objPtr != NULL) {
3004 if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", TCL_EXACT,
3005 &index) != TCL_OK) {
3013 for (i = start; i < end; i++) {
3016 str = faPtr->family;
3017 valuePtr = Tcl_NewStringObj(str, ((str == NULL) ? 0 : -1));
3021 valuePtr = Tcl_NewIntObj(faPtr->size);
3025 str = TkFindStateString(weightMap, faPtr->weight);
3026 valuePtr = Tcl_NewStringObj(str, -1);
3030 str = TkFindStateString(slantMap, faPtr->slant);
3031 valuePtr = Tcl_NewStringObj(str, -1);
3034 case FONT_UNDERLINE:
3035 valuePtr = Tcl_NewBooleanObj(faPtr->underline);
3038 case FONT_OVERSTRIKE:
3039 valuePtr = Tcl_NewBooleanObj(faPtr->overstrike);
3042 if (objPtr != NULL) {
3043 Tcl_SetObjResult(interp, valuePtr);
3046 optionPtr = Tcl_NewStringObj(fontOpt[i], -1);
3047 Tcl_ListObjAppendElement(NULL, resultPtr, optionPtr);
3048 Tcl_ListObjAppendElement(NULL, resultPtr, valuePtr);
3054 *---------------------------------------------------------------------------
3056 * ParseFontNameObj --
3058 * Converts a object into a set of font attributes that can be used
3059 * to construct a font.
3061 * The string rep of the object can be one of the following forms:
3062 * XLFD (see X documentation)
3063 * "family [size] [style1 [style2 ...]"
3064 * "-option value [-option value ...]"
3067 * The return value is TCL_ERROR if the object was syntactically
3068 * invalid. In that case an error message is left in interp's
3069 * result object. Otherwise, fills the font attribute buffer with
3070 * the values parsed from the string and returns TCL_OK;
3075 *---------------------------------------------------------------------------
3079 ParseFontNameObj(interp, tkwin, objPtr, faPtr)
3080 Tcl_Interp *interp; /* Interp for error return. Must not be
3082 Tk_Window tkwin; /* For display on which font is used. */
3083 Tcl_Obj *objPtr; /* Parseable font description object. */
3084 TkFontAttributes *faPtr; /* Filled with attributes parsed from font
3085 * name. Any attributes that were not
3086 * specified in font name are filled with
3087 * default values. */
3090 int objc, result, i, n;
3094 TkInitFontAttributes(faPtr);
3096 string = Tcl_GetString(objPtr);
3097 if (*string == '-') {
3099 * This may be an XLFD or an "-option value" string.
3101 * If the string begins with "-*" or a "-foundry-family-*" pattern,
3102 * then consider it an XLFD.
3105 if (string[1] == '*') {
3108 dash = strchr(string + 1, '-');
3110 && (!isspace(UCHAR(dash[-1])))) { /* INTL: ISO space */
3114 if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
3118 return ConfigAttributesObj(interp, tkwin, objc, objv, faPtr);
3121 if (*string == '*') {
3123 * This is appears to be an XLFD. Under Unix, all valid XLFDs were
3124 * already handled by TkpGetNativeFont. If we are here, either we
3125 * have something that initially looks like an XLFD but isn't or we
3126 * have encountered an XLFD on Windows or Mac.
3130 result = TkFontParseXLFD(string, faPtr, NULL);
3131 if (result == TCL_OK) {
3137 * Wasn't an XLFD or "-option value" string. Try it as a
3138 * "font size style" list.
3141 if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK)
3143 Tcl_AppendResult(interp, "font \"", string, "\" doesn't exist",
3148 faPtr->family = Tk_GetUid(Tcl_GetString(objv[0]));
3150 if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) {
3158 if (Tcl_ListObjGetElements(interp, objv[2], &objc, &objv) != TCL_OK) {
3163 for ( ; i < objc; i++) {
3164 n = TkFindStateNumObj(NULL, NULL, weightMap, objv[i]);
3165 if (n != TK_FW_UNKNOWN) {
3169 n = TkFindStateNumObj(NULL, NULL, slantMap, objv[i]);
3170 if (n != TK_FS_UNKNOWN) {
3174 n = TkFindStateNumObj(NULL, NULL, underlineMap, objv[i]);
3176 faPtr->underline = n;
3179 n = TkFindStateNumObj(NULL, NULL, overstrikeMap, objv[i]);
3181 faPtr->overstrike = n;
3189 Tcl_AppendResult(interp, "unknown font style \"",
3190 Tcl_GetString(objv[i]), "\"", (char *) NULL);
3197 *---------------------------------------------------------------------------
3201 * Helper function for Tk_ComputeTextLayout(). Encapsulates a
3202 * measured set of characters in a chunk that can be quickly
3206 * A pointer to the new chunk in the text layout.
3209 * The text layout is reallocated to hold more chunks as necessary.
3211 * Currently, Tk_ComputeTextLayout() stores contiguous ranges of
3212 * "normal" characters in a chunk, along with individual tab
3213 * and newline chars in their own chunks. All characters in the
3214 * text layout are accounted for.
3216 *---------------------------------------------------------------------------
3218 static LayoutChunk *
3219 NewChunk(layoutPtrPtr, maxPtr, start, numBytes, curX, newX, y)
3220 TextLayout **layoutPtrPtr;
3228 TextLayout *layoutPtr;
3229 LayoutChunk *chunkPtr;
3230 int maxChunks, numChars;
3233 layoutPtr = *layoutPtrPtr;
3234 maxChunks = *maxPtr;
3235 if (layoutPtr->numChunks == maxChunks) {
3237 s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk));
3238 layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s);
3240 *layoutPtrPtr = layoutPtr;
3241 *maxPtr = maxChunks;
3243 numChars = Tcl_NumUtfChars(start, numBytes);
3244 chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks];
3245 chunkPtr->start = start;
3246 chunkPtr->numBytes = numBytes;
3247 chunkPtr->numChars = numChars;
3248 chunkPtr->numDisplayChars = numChars;
3251 chunkPtr->totalWidth = newX - curX;
3252 chunkPtr->displayWidth = newX - curX;
3253 layoutPtr->numChunks++;
3259 *---------------------------------------------------------------------------
3261 * TkFontParseXLFD --
3263 * Break up a fully specified XLFD into a set of font attributes.
3266 * Return value is TCL_ERROR if string was not a fully specified XLFD.
3267 * Otherwise, fills font attribute buffer with the values parsed
3268 * from the XLFD and returns TCL_OK.
3273 *---------------------------------------------------------------------------
3277 TkFontParseXLFD(string, faPtr, xaPtr)
3278 CONST char *string; /* Parseable font description string. */
3279 TkFontAttributes *faPtr; /* Filled with attributes parsed from font
3280 * name. Any attributes that were not
3281 * specified in font name are filled with
3282 * default values. */
3283 TkXLFDAttributes *xaPtr; /* Filled with X-specific attributes parsed
3284 * from font name. Any attributes that were
3285 * not specified in font name are filled with
3286 * default values. May be NULL if such
3287 * information is not desired. */
3292 char *field[XLFD_NUMFIELDS + 2];
3294 TkXLFDAttributes xa;
3296 if (xaPtr == NULL) {
3299 TkInitFontAttributes(faPtr);
3300 TkInitXLFDAttributes(xaPtr);
3302 memset(field, '\0', sizeof(field));
3309 Tcl_DStringInit(&ds);
3310 Tcl_DStringAppend(&ds, (char *) str, -1);
3311 src = Tcl_DStringValue(&ds);
3314 for (i = 0; *src != '\0'; src++) {
3316 && Tcl_UniCharIsUpper(UCHAR(*src))) {
3317 *src = (char) Tcl_UniCharToLower(UCHAR(*src));
3321 if (i == XLFD_NUMFIELDS) {
3326 if (i > XLFD_NUMFIELDS) {
3333 * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common,
3334 * but it is (strictly) malformed, because the first * is eliding both
3335 * the Setwidth and the Addstyle fields. If the Addstyle field is a
3336 * number, then assume the above incorrect form was used and shift all
3337 * the rest of the fields right by one, so the number gets interpreted
3338 * as a pixelsize. This fix is so that we don't get a million reports
3339 * that "it works under X (as a native font name), but gives a syntax
3340 * error under Windows (as a parsed set of attributes)".
3343 if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) {
3344 if (atoi(field[XLFD_ADD_STYLE]) != 0) {
3345 for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) {
3346 field[j + 1] = field[j];
3348 field[XLFD_ADD_STYLE] = NULL;
3354 * Bail if we don't have enough of the fields (up to pointsize).
3357 if (i < XLFD_FAMILY) {
3358 Tcl_DStringFree(&ds);
3362 if (FieldSpecified(field[XLFD_FOUNDRY])) {
3363 xaPtr->foundry = Tk_GetUid(field[XLFD_FOUNDRY]);
3366 if (FieldSpecified(field[XLFD_FAMILY])) {
3367 faPtr->family = Tk_GetUid(field[XLFD_FAMILY]);
3369 if (FieldSpecified(field[XLFD_WEIGHT])) {
3370 faPtr->weight = TkFindStateNum(NULL, NULL, xlfdWeightMap,
3371 field[XLFD_WEIGHT]);
3373 if (FieldSpecified(field[XLFD_SLANT])) {
3374 xaPtr->slant = TkFindStateNum(NULL, NULL, xlfdSlantMap,
3376 if (xaPtr->slant == TK_FS_ROMAN) {
3377 faPtr->slant = TK_FS_ROMAN;
3379 faPtr->slant = TK_FS_ITALIC;
3382 if (FieldSpecified(field[XLFD_SETWIDTH])) {
3383 xaPtr->setwidth = TkFindStateNum(NULL, NULL, xlfdSetwidthMap,
3384 field[XLFD_SETWIDTH]);
3387 /* XLFD_ADD_STYLE ignored. */
3390 * Pointsize in tenths of a point, but treat it as tenths of a pixel
3391 * for historical compatibility.
3396 if (FieldSpecified(field[XLFD_POINT_SIZE])) {
3397 if (field[XLFD_POINT_SIZE][0] == '[') {
3399 * Some X fonts have the point size specified as follows:
3403 * where N1 is the point size (in points, not decipoints!), and
3404 * N2, N3, and N4 are some additional numbers that I don't know
3405 * the purpose of, so I ignore them.
3408 faPtr->size = atoi(field[XLFD_POINT_SIZE] + 1);
3409 } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE],
3410 &faPtr->size) == TCL_OK) {
3418 * Pixel height of font. If specified, overrides pointsize.
3421 if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {
3422 if (field[XLFD_PIXEL_SIZE][0] == '[') {
3424 * Some X fonts have the pixel size specified as follows:
3428 * where N1 is the pixel size, and where N2, N3, and N4
3429 * are some additional numbers that I don't know
3430 * the purpose of, so I ignore them.
3433 faPtr->size = atoi(field[XLFD_PIXEL_SIZE] + 1);
3434 } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE],
3435 &faPtr->size) != TCL_OK) {
3440 faPtr->size = -faPtr->size;
3442 /* XLFD_RESOLUTION_X ignored. */
3444 /* XLFD_RESOLUTION_Y ignored. */
3446 /* XLFD_SPACING ignored. */
3448 /* XLFD_AVERAGE_WIDTH ignored. */
3450 if (FieldSpecified(field[XLFD_CHARSET])) {
3451 xaPtr->charset = Tk_GetUid(field[XLFD_CHARSET]);
3453 xaPtr->charset = Tk_GetUid("iso8859-1");
3455 Tcl_DStringFree(&ds);
3460 *---------------------------------------------------------------------------
3464 * Helper function for TkParseXLFD(). Determines if a field in the
3465 * XLFD was set to a non-null, non-don't-care value.
3468 * The return value is 0 if the field in the XLFD was not set and
3469 * should be ignored, non-zero otherwise.
3474 *---------------------------------------------------------------------------
3478 FieldSpecified(field)
3479 CONST char *field; /* The field of the XLFD to check. Strictly
3480 * speaking, only when the string is "*" does it mean
3481 * don't-care. However, an unspecified or question
3482 * mark is also interpreted as don't-care. */
3486 if (field == NULL) {
3490 return (ch != '*' && ch != '?');
3494 *---------------------------------------------------------------------------
3496 * TkFontGetPixels --
3498 * Given a font size specification (as described in the TkFontAttributes
3499 * structure) return the number of pixels it represents.
3507 *---------------------------------------------------------------------------
3511 TkFontGetPixels(tkwin, size)
3512 Tk_Window tkwin; /* For point->pixel conversion factor. */
3513 int size; /* Font size. */
3521 d = size * 25.4 / 72.0;
3522 d *= WidthOfScreen(Tk_Screen(tkwin));
3523 d /= WidthMMOfScreen(Tk_Screen(tkwin));
3524 return (int) (d + 0.5);
3528 *---------------------------------------------------------------------------
3530 * TkFontGetPoints --
3532 * Given a font size specification (as described in the TkFontAttributes
3533 * structure) return the number of points it represents.
3541 *---------------------------------------------------------------------------
3545 TkFontGetPoints(tkwin, size)
3546 Tk_Window tkwin; /* For pixel->point conversion factor. */
3547 int size; /* Font size. */
3555 d = -size * 72.0 / 25.4;
3556 d *= WidthMMOfScreen(Tk_Screen(tkwin));
3557 d /= WidthOfScreen(Tk_Screen(tkwin));
3558 return (int) (d + 0.5);
3562 *-------------------------------------------------------------------------
3564 * TkFontGetAliasList --
3566 * Given a font name, find the list of all aliases for that font
3567 * name. One of the names in this list will probably be the name
3568 * that this platform expects when asking for the font.
3571 * As above. The return value is NULL if the font name has no
3577 *-------------------------------------------------------------------------
3581 TkFontGetAliasList(faceName)
3582 CONST char *faceName; /* Font name to test for aliases. */
3586 for (i = 0; fontAliases[i] != NULL; i++) {
3587 for (j = 0; fontAliases[i][j] != NULL; j++) {
3588 if (strcasecmp(faceName, fontAliases[i][j]) == 0) {
3589 return fontAliases[i];
3597 *-------------------------------------------------------------------------
3599 * TkFontGetFallbacks --
3601 * Get the list of font fallbacks that the platform-specific code
3602 * can use to try to find the closest matching font the name
3611 *-------------------------------------------------------------------------
3615 TkFontGetFallbacks()
3617 return fontFallbacks;
3621 *-------------------------------------------------------------------------
3623 * TkFontGetGlobalClass --
3625 * Get the list of fonts to try if the requested font name does not
3626 * exist and no fallbacks for that font name could be used either.
3627 * The names in this list are considered preferred over all the other
3628 * font names in the system when looking for a last-ditch fallback.
3636 *-------------------------------------------------------------------------
3640 TkFontGetGlobalClass()
3642 return globalFontClass;
3646 *-------------------------------------------------------------------------
3648 * TkFontGetSymbolClass --
3650 * Get the list of fonts that are symbolic; used if the operating
3651 * system cannot apriori identify symbolic fonts on its own.
3659 *-------------------------------------------------------------------------
3663 TkFontGetSymbolClass()
3669 *----------------------------------------------------------------------
3673 * This procedure returns debugging information about a font.
3676 * The return value is a list with one sublist for each TkFont
3677 * corresponding to "name". Each sublist has two elements that
3678 * contain the resourceRefCount and objRefCount fields from the
3684 *----------------------------------------------------------------------
3688 TkDebugFont(tkwin, name)
3689 Tk_Window tkwin; /* The window in which the font will be
3690 * used (not currently used). */
3691 char *name; /* Name of the desired color. */
3694 Tcl_HashEntry *hashPtr;
3695 Tcl_Obj *resultPtr, *objPtr;
3697 resultPtr = Tcl_NewObj();
3698 hashPtr = Tcl_FindHashEntry(
3699 &((TkWindow *) tkwin)->mainPtr->fontInfoPtr->fontCache, name);
3700 if (hashPtr != NULL) {
3701 fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr);
3702 if (fontPtr == NULL) {
3703 panic("TkDebugFont found empty hash table entry");
3705 for ( ; (fontPtr != NULL); fontPtr = fontPtr->nextPtr) {
3706 objPtr = Tcl_NewObj();
3707 Tcl_ListObjAppendElement(NULL, objPtr,
3708 Tcl_NewIntObj(fontPtr->resourceRefCount));
3709 Tcl_ListObjAppendElement(NULL, objPtr,
3710 Tcl_NewIntObj(fontPtr->objRefCount));
3711 Tcl_ListObjAppendElement(NULL, resultPtr, objPtr);
3718 *----------------------------------------------------------------------
3720 * TkFontGetFirstTextLayout --
3722 * This procedure returns the first chunk of a Tk_TextLayout,
3723 * i.e. until the first font change on the first line (or the
3724 * whole first line if there is no such font change).
3727 * The return value is the byte length of the chunk, the chunk
3728 * itself is copied into dst and its Tk_Font into font.
3733 *----------------------------------------------------------------------
3737 TkFontGetFirstTextLayout(
3738 Tk_TextLayout layout, /* Layout information, from a previous call
3739 * to Tk_ComputeTextLayout(). */
3743 TextLayout *layoutPtr;
3744 LayoutChunk *chunkPtr;
3745 int numBytesInChunk;
3747 layoutPtr = (TextLayout *)layout;
3748 if ((layoutPtr==NULL)
3749 || (layoutPtr->numChunks==0)
3750 || (layoutPtr->chunks->numDisplayChars <= 0)) {
3754 chunkPtr = layoutPtr->chunks;
3755 numBytesInChunk = chunkPtr->numBytes;
3756 strncpy(dst, chunkPtr->start, (size_t) numBytesInChunk);
3757 *font = layoutPtr->tkfont;
3758 return numBytesInChunk;