tkFont.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:102k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkFont.c --
  3.  *
  4.  * This file maintains a database of fonts for the Tk toolkit.
  5.  * It also provides several utility procedures for measuring and
  6.  * displaying text.
  7.  *
  8.  * Copyright (c) 1990-1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1998 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tkFont.c,v 1.21.2.2 2007/05/31 13:39:26 das Exp $
  15.  */
  16. #include "tkPort.h"
  17. #include "tkInt.h"
  18. #include "tkFont.h"
  19. /*
  20.  * The following structure is used to keep track of all the fonts that
  21.  * exist in the current application.  It must be stored in the
  22.  * TkMainInfo for the application.
  23.  */
  24.  
  25. typedef struct TkFontInfo {
  26.     Tcl_HashTable fontCache; /* Map a string to an existing Tk_Font.
  27.  * Keys are string font names, values are
  28.  * TkFont pointers. */
  29.     Tcl_HashTable namedTable; /* Map a name to a set of attributes for a
  30.  * font, used when constructing a Tk_Font from
  31.  * a named font description.  Keys are
  32.  * strings, values are NamedFont pointers. */
  33.     TkMainInfo *mainPtr; /* Application that owns this structure. */
  34.     int updatePending; /* Non-zero when a World Changed event has
  35.  * already been queued to handle a change to
  36.  * a named font. */
  37. } TkFontInfo;
  38. /*
  39.  * The following data structure is used to keep track of the font attributes
  40.  * for each named font that has been defined.  The named font is only deleted
  41.  * when the last reference to it goes away.
  42.  */
  43. typedef struct NamedFont {
  44.     int refCount; /* Number of users of named font. */
  45.     int deletePending; /* Non-zero if font should be deleted when
  46.  * last reference goes away. */
  47.     TkFontAttributes fa; /* Desired attributes for named font. */
  48. } NamedFont;
  49.     
  50. /*
  51.  * The following two structures are used to keep track of string
  52.  * measurement information when using the text layout facilities.
  53.  *
  54.  * A LayoutChunk represents a contiguous range of text that can be measured
  55.  * and displayed by low-level text calls.  In general, chunks will be
  56.  * delimited by newlines and tabs.  Low-level, platform-specific things
  57.  * like kerning and non-integer character widths may occur between the
  58.  * characters in a single chunk, but not between characters in different
  59.  * chunks.
  60.  *
  61.  * A TextLayout is a collection of LayoutChunks.  It can be displayed with
  62.  * respect to any origin.  It is the implementation of the Tk_TextLayout
  63.  * opaque token.
  64.  */
  65. typedef struct LayoutChunk {
  66.     CONST char *start; /* Pointer to simple string to be displayed.
  67.  * This is a pointer into the TkTextLayout's
  68.  * string. */
  69.     int numBytes; /* The number of bytes in this chunk. */
  70.     int numChars; /* The number of characters in this chunk. */
  71.     int numDisplayChars; /* The number of characters to display when
  72.  * this chunk is displayed.  Can be less than
  73.  * numChars if extra space characters were
  74.  * absorbed by the end of the chunk.  This
  75.  * will be < 0 if this is a chunk that is
  76.  * holding a tab or newline. */
  77.     int x, y; /* The origin of the first character in this
  78.  * chunk with respect to the upper-left hand
  79.  * corner of the TextLayout. */
  80.     int totalWidth; /* Width in pixels of this chunk.  Used
  81.  * when hit testing the invisible spaces at
  82.  * the end of a chunk. */
  83.     int displayWidth; /* Width in pixels of the displayable
  84.  * characters in this chunk.  Can be less than
  85.  * width if extra space characters were
  86.  * absorbed by the end of the chunk. */
  87. } LayoutChunk;
  88. typedef struct TextLayout {
  89.     Tk_Font tkfont; /* The font used when laying out the text. */
  90.     CONST char *string; /* The string that was layed out. */
  91.     int width; /* The maximum width of all lines in the
  92.  * text layout. */
  93.     int numChunks; /* Number of chunks actually used in
  94.  * following array. */
  95.     LayoutChunk chunks[1]; /* Array of chunks.  The actual size will
  96.  * be maxChunks.  THIS FIELD MUST BE THE LAST
  97.  * IN THE STRUCTURE. */
  98. } TextLayout;
  99. /*
  100.  * The following structures are used as two-way maps between the values for
  101.  * the fields in the TkFontAttributes structure and the strings used in
  102.  * Tcl, when parsing both option-value format and style-list format font
  103.  * name strings.
  104.  */
  105. static TkStateMap weightMap[] = {
  106.     {TK_FW_NORMAL, "normal"},
  107.     {TK_FW_BOLD, "bold"},
  108.     {TK_FW_UNKNOWN, NULL}
  109. };
  110. static TkStateMap slantMap[] = {
  111.     {TK_FS_ROMAN, "roman"},
  112.     {TK_FS_ITALIC, "italic"},
  113.     {TK_FS_UNKNOWN, NULL}
  114. };
  115. static TkStateMap underlineMap[] = {
  116.     {1, "underline"},
  117.     {0, NULL}
  118. };
  119. static TkStateMap overstrikeMap[] = {
  120.     {1, "overstrike"},
  121.     {0, NULL}
  122. };
  123. /*
  124.  * The following structures are used when parsing XLFD's into a set of
  125.  * TkFontAttributes.
  126.  */
  127. static TkStateMap xlfdWeightMap[] = {
  128.     {TK_FW_NORMAL, "normal"},
  129.     {TK_FW_NORMAL, "medium"},
  130.     {TK_FW_NORMAL, "book"},
  131.     {TK_FW_NORMAL, "light"},
  132.     {TK_FW_BOLD, "bold"},
  133.     {TK_FW_BOLD, "demi"},
  134.     {TK_FW_BOLD, "demibold"},
  135.     {TK_FW_NORMAL, NULL} /* Assume anything else is "normal". */
  136. }; 
  137. static TkStateMap xlfdSlantMap[] = {
  138.     {TK_FS_ROMAN, "r"},
  139.     {TK_FS_ITALIC, "i"},
  140.     {TK_FS_OBLIQUE, "o"},
  141.     {TK_FS_ROMAN, NULL} /* Assume anything else is "roman". */
  142. };
  143. static TkStateMap xlfdSetwidthMap[] = {
  144.     {TK_SW_NORMAL, "normal"},
  145.     {TK_SW_CONDENSE, "narrow"},
  146.     {TK_SW_CONDENSE, "semicondensed"},
  147.     {TK_SW_CONDENSE, "condensed"},
  148.     {TK_SW_UNKNOWN, NULL}
  149. };
  150. /*
  151.  * The following structure and defines specify the valid builtin options 
  152.  * when configuring a set of font attributes.
  153.  */
  154. static CONST char *fontOpt[] = {
  155.     "-family",
  156.     "-size",
  157.     "-weight",
  158.     "-slant",
  159.     "-underline",
  160.     "-overstrike",
  161.     NULL
  162. };
  163. #define FONT_FAMILY 0
  164. #define FONT_SIZE 1
  165. #define FONT_WEIGHT 2
  166. #define FONT_SLANT 3
  167. #define FONT_UNDERLINE 4
  168. #define FONT_OVERSTRIKE 5
  169. #define FONT_NUMFIELDS 6
  170. /*
  171.  * Hardcoded font aliases.  These are used to describe (mostly) identical
  172.  * fonts whose names differ from platform to platform.  If the
  173.  * user-supplied font name matches any of the names in one of the alias
  174.  * lists, the other names in the alias list are also automatically tried.
  175.  */
  176. static char *timesAliases[] = {
  177.     "Times", /* Unix. */
  178.     "Times New Roman", /* Windows. */
  179.     "New York", /* Mac. */
  180.     NULL
  181. };
  182. static char *helveticaAliases[] = {
  183.     "Helvetica", /* Unix. */
  184.     "Arial", /* Windows. */
  185.     "Geneva", /* Mac. */
  186.     NULL
  187. };
  188. static char *courierAliases[] = {
  189.     "Courier", /* Unix and Mac. */
  190.     "Courier New", /* Windows. */
  191.     NULL
  192. };
  193. static char *minchoAliases[] = {
  194.     "mincho", /* Unix. */
  195.     "357274255357274263 346230216346234235",
  196. /* Windows (MS mincho). */
  197.     "346234254346230216346234235342210222357274255",
  198. /* Mac (honmincho-M). */
  199.     NULL
  200. };
  201. static char *gothicAliases[] = {
  202.     "gothic", /* Unix. */
  203.     "357274255357274263 343202264343202267343203203343202257",
  204. /* Windows (MS goshikku). */
  205.     "344270270343202264343202267343203203343202257342210222357274255",
  206. /* Mac (goshikku-M). */
  207.     NULL    
  208. };
  209. static char *dingbatsAliases[] = {
  210.     "dingbats", "zapfdingbats", "itc zapfdingbats",
  211. /* Unix. */
  212. /* Windows. */
  213.     "zapf dingbats", /* Mac. */
  214.     NULL
  215. };
  216. static char **fontAliases[] = {
  217.     timesAliases,
  218.     helveticaAliases,
  219.     courierAliases,
  220.     minchoAliases,
  221.     gothicAliases,
  222.     dingbatsAliases,
  223.     NULL
  224. };  
  225. /*
  226.  * Hardcoded font classes.  If the character cannot be found in the base 
  227.  * font, the classes are examined in order to see if some other similar 
  228.  * font should be examined also.  
  229.  */
  230. static char *systemClass[] = {
  231.     "fixed", /* Unix. */
  232. /* Windows. */
  233.     "chicago", "osaka", "sistemny", /* Mac. */
  234.     NULL
  235. };
  236. static char *serifClass[] = {
  237.     "times", "palatino", "mincho", /* All platforms. */
  238.     "song ti", /* Unix. */
  239.     "ms serif", "simplified arabic",  /* Windows. */
  240.     "latinski", /* Mac. */
  241.     NULL
  242. };
  243. static char *sansClass[] = {
  244.     "helvetica", "gothic", /* All platforms. */
  245. /* Unix. */
  246.     "ms sans serif", "traditional arabic",
  247. /* Windows. */
  248.     "bastion", /* Mac. */
  249.     NULL
  250. };
  251. static char *monoClass[] = {
  252.     "courier", "gothic", /* All platforms. */
  253.     "fangsong ti", /* Unix. */
  254.     "simplified arabic fixed", /* Windows. */
  255.     "monaco", "pryamoy", /* Mac. */
  256.     NULL
  257. };
  258. static char *symbolClass[] = {
  259.     "symbol", "dingbats", "wingdings", NULL
  260. };
  261. static char **fontFallbacks[] = {
  262.     systemClass,
  263.     serifClass,
  264.     sansClass,
  265.     monoClass,
  266.     symbolClass,
  267.     NULL
  268. };
  269. /*
  270.  * Global fallbacks.  If the character could not be found in the preferred
  271.  * fallback list, this list is examined.  If the character still cannot be
  272.  * found, all font families in the system are examined. 
  273.  */
  274. static char *globalFontClass[] = {
  275.     "symbol", /* All platforms. */
  276. /* Unix. */
  277.     "lucida sans unicode", /* Windows. */
  278.     "bitstream cyberbit", /* Windows popular CJK font */
  279.     "chicago", /* Mac. */
  280.     NULL
  281. };
  282. #define GetFontAttributes(tkfont) 
  283. ((CONST TkFontAttributes *) &((TkFont *) (tkfont))->fa)
  284. #define GetFontMetrics(tkfont)    
  285. ((CONST TkFontMetrics *) &((TkFont *) (tkfont))->fm)
  286. static int ConfigAttributesObj _ANSI_ARGS_((Tcl_Interp *interp,
  287.     Tk_Window tkwin, int objc, Tcl_Obj *CONST objv[],
  288.     TkFontAttributes *faPtr));
  289. static int CreateNamedFont _ANSI_ARGS_((Tcl_Interp *interp,
  290.     Tk_Window tkwin, CONST char *name,
  291.     TkFontAttributes *faPtr));
  292. static void DupFontObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,
  293.     Tcl_Obj *dupObjPtr));
  294. static int FieldSpecified _ANSI_ARGS_((CONST char *field));
  295. static void FreeFontObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));
  296. static int GetAttributeInfoObj _ANSI_ARGS_((Tcl_Interp *interp,
  297.     CONST TkFontAttributes *faPtr, Tcl_Obj *objPtr));
  298. static LayoutChunk * NewChunk _ANSI_ARGS_((TextLayout **layoutPtrPtr,
  299.     int *maxPtr, CONST char *start, int numChars,
  300.     int curX, int newX, int y));
  301. static int ParseFontNameObj _ANSI_ARGS_((Tcl_Interp *interp,
  302.     Tk_Window tkwin, Tcl_Obj *objPtr,
  303.     TkFontAttributes *faPtr));
  304. static void RecomputeWidgets _ANSI_ARGS_((TkWindow *winPtr));
  305. static int SetFontFromAny _ANSI_ARGS_((Tcl_Interp *interp,
  306.     Tcl_Obj *objPtr));
  307. static void TheWorldHasChanged _ANSI_ARGS_((
  308.     ClientData clientData));
  309. static void UpdateDependentFonts _ANSI_ARGS_((TkFontInfo *fiPtr,
  310.     Tk_Window tkwin, Tcl_HashEntry *namedHashPtr));
  311. /*
  312.  * The following structure defines the implementation of the "font" Tcl
  313.  * object, used for drawing. The internalRep.twoPtrValue.ptr1 field of
  314.  * each font object points to the TkFont structure for the font, or
  315.  * NULL.
  316.  */
  317. Tcl_ObjType tkFontObjType = {
  318.     "font", /* name */
  319.     FreeFontObjProc, /* freeIntRepProc */
  320.     DupFontObjProc, /* dupIntRepProc */
  321.     NULL, /* updateStringProc */
  322.     SetFontFromAny /* setFromAnyProc */
  323. };
  324. /*
  325.  *---------------------------------------------------------------------------
  326.  *
  327.  * TkFontPkgInit --
  328.  *
  329.  * This procedure is called when an application is created.  It
  330.  * initializes all the structures that are used by the font
  331.  * package on a per application basis.
  332.  *
  333.  * Results:
  334.  * Stores a token in the mainPtr to hold information needed by this 
  335.  * package on a per application basis. 
  336.  *
  337.  * Side effects:
  338.  * Memory allocated.
  339.  *
  340.  *---------------------------------------------------------------------------
  341.  */
  342. void
  343. TkFontPkgInit(mainPtr)
  344.     TkMainInfo *mainPtr; /* The application being created. */
  345. {
  346.     TkFontInfo *fiPtr;
  347.     fiPtr = (TkFontInfo *) ckalloc(sizeof(TkFontInfo));
  348.     Tcl_InitHashTable(&fiPtr->fontCache, TCL_STRING_KEYS);
  349.     Tcl_InitHashTable(&fiPtr->namedTable, TCL_STRING_KEYS);
  350.     fiPtr->mainPtr = mainPtr;
  351.     fiPtr->updatePending = 0;
  352.     mainPtr->fontInfoPtr = fiPtr;
  353.     TkpFontPkgInit(mainPtr);
  354. }
  355. /*
  356.  *---------------------------------------------------------------------------
  357.  *
  358.  * TkFontPkgFree --
  359.  *
  360.  * This procedure is called when an application is deleted.  It
  361.  * deletes all the structures that were used by the font package
  362.  * for this application.
  363.  *
  364.  * Results:
  365.  * None.
  366.  *
  367.  * Side effects:
  368.  * Memory freed.
  369.  *
  370.  *---------------------------------------------------------------------------
  371.  */
  372. void
  373. TkFontPkgFree(mainPtr)
  374.     TkMainInfo *mainPtr; /* The application being deleted. */
  375. {
  376.     TkFontInfo *fiPtr;
  377.     Tcl_HashEntry *hPtr, *searchPtr;
  378.     Tcl_HashSearch search;
  379.     int fontsLeft;
  380.     fiPtr = mainPtr->fontInfoPtr;
  381.     fontsLeft = 0;
  382.     for (searchPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);
  383.     searchPtr != NULL;
  384.     searchPtr = Tcl_NextHashEntry(&search)) {
  385. fontsLeft++;
  386. #ifdef DEBUG_FONTS
  387. fprintf(stderr, "Font %s still in cache.n", 
  388. Tcl_GetHashKey(&fiPtr->fontCache, searchPtr));
  389. #endif
  390.     }
  391. #ifdef PURIFY
  392.     if (fontsLeft) {
  393. panic("TkFontPkgFree: all fonts should have been freed already");
  394.     }
  395. #endif
  396.     Tcl_DeleteHashTable(&fiPtr->fontCache);
  397.     hPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
  398.     while (hPtr != NULL) {
  399. ckfree((char *) Tcl_GetHashValue(hPtr));
  400. hPtr = Tcl_NextHashEntry(&search);
  401.     }
  402.     Tcl_DeleteHashTable(&fiPtr->namedTable);
  403.     if (fiPtr->updatePending != 0) {
  404. Tcl_CancelIdleCall(TheWorldHasChanged, (ClientData) fiPtr);
  405.     }
  406.     ckfree((char *) fiPtr);
  407. }
  408. /*
  409.  *---------------------------------------------------------------------------
  410.  *
  411.  * Tk_FontObjCmd -- 
  412.  *
  413.  * This procedure is implemented to process the "font" Tcl command.
  414.  * See the user documentation for details on what it does.
  415.  *
  416.  * Results:
  417.  * A standard Tcl result.
  418.  *
  419.  * Side effects:
  420.  * See the user documentation.
  421.  *
  422.  *----------------------------------------------------------------------
  423.  */
  424. int
  425. Tk_FontObjCmd(clientData, interp, objc, objv)
  426.     ClientData clientData; /* Main window associated with interpreter. */
  427.     Tcl_Interp *interp; /* Current interpreter. */
  428.     int objc; /* Number of arguments. */
  429.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  430. {
  431.     int index;
  432.     Tk_Window tkwin;
  433.     TkFontInfo *fiPtr;
  434.     static CONST char *optionStrings[] = {
  435. "actual", "configure", "create", "delete",
  436. "families", "measure", "metrics", "names",
  437. NULL
  438.     };
  439.     enum options {
  440. FONT_ACTUAL, FONT_CONFIGURE, FONT_CREATE, FONT_DELETE,
  441. FONT_FAMILIES, FONT_MEASURE, FONT_METRICS, FONT_NAMES
  442.     };
  443.     tkwin = (Tk_Window) clientData;
  444.     fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
  445.     if (objc < 2) {
  446. Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");
  447. return TCL_ERROR;
  448.     }
  449.     if (Tcl_GetIndexFromObj(interp, objv[1], optionStrings, "option", 0,
  450.     &index) != TCL_OK) {
  451. return TCL_ERROR;
  452.     }
  453.     switch ((enum options) index) {
  454. case FONT_ACTUAL: {
  455.     int skip, result;
  456.     Tk_Font tkfont;
  457.     Tcl_Obj *objPtr;
  458.     CONST TkFontAttributes *faPtr;
  459.     skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
  460.     if (skip < 0) {
  461. return TCL_ERROR;
  462.     }
  463.     if ((objc < 3) || (objc - skip > 4)) {
  464. Tcl_WrongNumArgs(interp, 2, objv,
  465. "font ?-displayof window? ?option?");
  466. return TCL_ERROR;
  467.     }
  468.     tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
  469.     if (tkfont == NULL) {
  470. return TCL_ERROR;
  471.     }
  472.     objc -= skip;
  473.     objv += skip;
  474.     faPtr = GetFontAttributes(tkfont);
  475.     objPtr = NULL;
  476.     if (objc > 3) {
  477. objPtr = objv[3];
  478.     }
  479.     result = GetAttributeInfoObj(interp, faPtr, objPtr);
  480.     Tk_FreeFont(tkfont);
  481.     return result;
  482. }
  483. case FONT_CONFIGURE: {
  484.     int result;
  485.     char *string;
  486.     Tcl_Obj *objPtr;
  487.     NamedFont *nfPtr;
  488.     Tcl_HashEntry *namedHashPtr;
  489.     if (objc < 3) {
  490. Tcl_WrongNumArgs(interp, 2, objv, "fontname ?options?");
  491. return TCL_ERROR;
  492.     }
  493.     string = Tcl_GetString(objv[2]);
  494.     namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
  495.     nfPtr = NULL; /* lint. */
  496.     if (namedHashPtr != NULL) {
  497. nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
  498.     }
  499.     if ((namedHashPtr == NULL) || (nfPtr->deletePending != 0)) {
  500. Tcl_AppendResult(interp, "named font "", string,
  501. "" doesn't exist", NULL);
  502. return TCL_ERROR;
  503.     }
  504.     if (objc == 3) {
  505. objPtr = NULL;
  506.     } else if (objc == 4) {
  507. objPtr = objv[3];
  508.     } else {
  509. result = ConfigAttributesObj(interp, tkwin, objc - 3,
  510. objv + 3, &nfPtr->fa);
  511. UpdateDependentFonts(fiPtr, tkwin, namedHashPtr);
  512. return result;
  513.     }
  514.     return GetAttributeInfoObj(interp, &nfPtr->fa, objPtr);
  515. }
  516. case FONT_CREATE: {
  517.     int skip, i;
  518.     char *name;
  519.     char buf[16 + TCL_INTEGER_SPACE];
  520.     TkFontAttributes fa;
  521.     Tcl_HashEntry *namedHashPtr;
  522.     skip = 3;
  523.     if (objc < 3) {
  524. name = NULL;
  525.     } else {
  526. name = Tcl_GetString(objv[2]);
  527. if (name[0] == '-') {
  528.     name = NULL;
  529. }
  530.     }
  531.     if (name == NULL) {
  532. /*
  533.  * No font name specified.  Generate one of the form "fontX".
  534.  */
  535. for (i = 1; ; i++) {
  536.     sprintf(buf, "font%d", i);
  537.     namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, buf);
  538.     if (namedHashPtr == NULL) {
  539. break;
  540.     }
  541. }
  542. name = buf;
  543. skip = 2;
  544.     }
  545.     TkInitFontAttributes(&fa);
  546.     if (ConfigAttributesObj(interp, tkwin, objc - skip, objv + skip,
  547.     &fa) != TCL_OK) {
  548. return TCL_ERROR;
  549.     }
  550.     if (CreateNamedFont(interp, tkwin, name, &fa) != TCL_OK) {
  551. return TCL_ERROR;
  552.     }
  553.     Tcl_AppendResult(interp, name, NULL);
  554.     break;
  555. }
  556. case FONT_DELETE: {
  557.     int i;
  558.     char *string;
  559.     NamedFont *nfPtr;
  560.     Tcl_HashEntry *namedHashPtr;
  561.     /*
  562.      * Delete the named font.  If there are still widgets using this
  563.      * font, then it isn't deleted right away.
  564.      */
  565.     if (objc < 3) {
  566. Tcl_WrongNumArgs(interp, 2, objv, "fontname ?fontname ...?");
  567. return TCL_ERROR;
  568.     }
  569.     for (i = 2; i < objc; i++) {
  570. string = Tcl_GetString(objv[i]);
  571. namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable, string);
  572. if (namedHashPtr == NULL) {
  573.     Tcl_AppendResult(interp, "named font "", string,
  574.     "" doesn't exist", (char *) NULL);
  575.     return TCL_ERROR;
  576. }
  577. nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
  578. if (nfPtr->refCount != 0) {
  579.     nfPtr->deletePending = 1;
  580. } else {
  581.     Tcl_DeleteHashEntry(namedHashPtr);
  582.     ckfree((char *) nfPtr);
  583. }
  584.     }
  585.     break;
  586. }
  587. case FONT_FAMILIES: {
  588.     int skip;
  589.     skip = TkGetDisplayOf(interp, objc - 2, objv + 2, &tkwin);
  590.     if (skip < 0) {
  591. return TCL_ERROR;
  592.     }
  593.     if (objc - skip != 2) {
  594. Tcl_WrongNumArgs(interp, 2, objv, "?-displayof window?");
  595. return TCL_ERROR;
  596.     }
  597.     TkpGetFontFamilies(interp, tkwin);
  598.     break;
  599. }
  600. case FONT_MEASURE: {
  601.     char *string;
  602.     Tk_Font tkfont;
  603.     int length, skip;
  604.     Tcl_Obj *resultPtr;
  605.     
  606.     skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
  607.     if (skip < 0) {
  608. return TCL_ERROR;
  609.     }
  610.     if (objc - skip != 4) {
  611. Tcl_WrongNumArgs(interp, 2, objv,
  612. "font ?-displayof window? text");
  613. return TCL_ERROR;
  614.     }
  615.     tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
  616.     if (tkfont == NULL) {
  617. return TCL_ERROR;
  618.     }
  619.     string = Tcl_GetStringFromObj(objv[3 + skip], &length);
  620.     resultPtr = Tcl_GetObjResult(interp);
  621.     Tcl_SetIntObj(resultPtr, Tk_TextWidth(tkfont, string, length));
  622.     Tk_FreeFont(tkfont);
  623.     break;
  624. }
  625. case FONT_METRICS: {
  626.     Tk_Font tkfont;
  627.     int skip, index, i;
  628.     CONST TkFontMetrics *fmPtr;
  629.     static CONST char *switches[] = {
  630. "-ascent", "-descent", "-linespace", "-fixed", NULL
  631.     };
  632.     skip = TkGetDisplayOf(interp, objc - 3, objv + 3, &tkwin);
  633.     if (skip < 0) {
  634. return TCL_ERROR;
  635.     }
  636.     if ((objc < 3) || ((objc - skip) > 4)) {
  637. Tcl_WrongNumArgs(interp, 2, objv,
  638. "font ?-displayof window? ?option?");
  639. return TCL_ERROR;
  640.     }
  641.     tkfont = Tk_AllocFontFromObj(interp, tkwin, objv[2]);
  642.     if (tkfont == NULL) {
  643. return TCL_ERROR;
  644.     }
  645.     objc -= skip;
  646.     objv += skip;
  647.     fmPtr = GetFontMetrics(tkfont);
  648.     if (objc == 3) {
  649. char buf[64 + TCL_INTEGER_SPACE * 4];
  650. sprintf(buf, "-ascent %d -descent %d -linespace %d -fixed %d",
  651. fmPtr->ascent, fmPtr->descent,
  652. fmPtr->ascent + fmPtr->descent,
  653. fmPtr->fixed);
  654. Tcl_AppendResult(interp, buf, NULL);
  655.     } else {
  656. if (Tcl_GetIndexFromObj(interp, objv[3], switches,
  657. "metric", 0, &index) != TCL_OK) {
  658.     Tk_FreeFont(tkfont);
  659.     return TCL_ERROR;
  660. }
  661. i = 0; /* Needed only to prevent compiler
  662.  * warning. */
  663. switch (index) {
  664.     case 0: i = fmPtr->ascent; break;
  665.     case 1: i = fmPtr->descent; break;
  666.     case 2: i = fmPtr->ascent + fmPtr->descent; break;
  667.     case 3: i = fmPtr->fixed; break;
  668. }
  669. Tcl_SetIntObj(Tcl_GetObjResult(interp), i);
  670.     }
  671.     Tk_FreeFont(tkfont);
  672.     break;
  673. }
  674. case FONT_NAMES: {
  675.     char *string;
  676.     NamedFont *nfPtr;
  677.     Tcl_HashSearch search;
  678.     Tcl_HashEntry *namedHashPtr;
  679.     Tcl_Obj *strPtr, *resultPtr;
  680.     
  681.     if (objc != 2) {
  682. Tcl_WrongNumArgs(interp, 1, objv, "names");
  683. return TCL_ERROR;
  684.     }
  685.     resultPtr = Tcl_GetObjResult(interp);
  686.     namedHashPtr = Tcl_FirstHashEntry(&fiPtr->namedTable, &search);
  687.     while (namedHashPtr != NULL) {
  688. nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
  689. if (nfPtr->deletePending == 0) {
  690.     string = Tcl_GetHashKey(&fiPtr->namedTable, namedHashPtr);
  691.     strPtr = Tcl_NewStringObj(string, -1);
  692.     Tcl_ListObjAppendElement(NULL, resultPtr, strPtr);
  693. }
  694. namedHashPtr = Tcl_NextHashEntry(&search);
  695.     }
  696.     break;
  697. }
  698.     }
  699.     return TCL_OK;
  700. }
  701. /*
  702.  *---------------------------------------------------------------------------
  703.  *
  704.  * UpdateDependentFonts, TheWorldHasChanged, RecomputeWidgets --
  705.  *
  706.  * Called when the attributes of a named font changes.  Updates all
  707.  * the instantiated fonts that depend on that named font and then
  708.  * uses the brute force approach and prepares every widget to
  709.  * recompute its geometry.
  710.  *
  711.  * Results:
  712.  * None.
  713.  *
  714.  * Side effects:
  715.  * Things get queued for redisplay.
  716.  *
  717.  *---------------------------------------------------------------------------
  718.  */
  719. static void
  720. UpdateDependentFonts(fiPtr, tkwin, namedHashPtr)
  721.     TkFontInfo *fiPtr; /* Info about application's fonts. */
  722.     Tk_Window tkwin; /* A window in the application. */
  723.     Tcl_HashEntry *namedHashPtr;/* The named font that is changing. */
  724. {
  725.     Tcl_HashEntry *cacheHashPtr;
  726.     Tcl_HashSearch search;
  727.     TkFont *fontPtr;
  728.     NamedFont *nfPtr;
  729.     nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
  730.     if (nfPtr->refCount == 0) {
  731. /*
  732.  * Well nobody's using this named font, so don't have to tell
  733.  * any widgets to recompute themselves.
  734.  */
  735. return;
  736.     }
  737.     cacheHashPtr = Tcl_FirstHashEntry(&fiPtr->fontCache, &search);
  738.     while (cacheHashPtr != NULL) {
  739. for (fontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
  740. fontPtr != NULL; fontPtr = fontPtr->nextPtr) {
  741.     if (fontPtr->namedHashPtr == namedHashPtr) {
  742. TkpGetFontFromAttributes(fontPtr, tkwin, &nfPtr->fa);
  743. if (fiPtr->updatePending == 0) {
  744.     fiPtr->updatePending = 1;
  745.     Tcl_DoWhenIdle(TheWorldHasChanged, (ClientData) fiPtr);
  746. }
  747.     }
  748. }
  749. cacheHashPtr = Tcl_NextHashEntry(&search);
  750.     }
  751. }
  752. static void
  753. TheWorldHasChanged(clientData)
  754.     ClientData clientData; /* Info about application's fonts. */
  755. {
  756.     TkFontInfo *fiPtr;
  757.     fiPtr = (TkFontInfo *) clientData;
  758.     fiPtr->updatePending = 0;
  759.     RecomputeWidgets(fiPtr->mainPtr->winPtr);
  760. }
  761. static void
  762. RecomputeWidgets(winPtr)
  763.     TkWindow *winPtr; /* Window to which command is sent. */
  764. {
  765.     Tk_ClassWorldChangedProc *proc;
  766.     proc = Tk_GetClassProc(winPtr->classProcsPtr, worldChangedProc);
  767.     if (proc != NULL) {
  768. (*proc)(winPtr->instanceData);
  769.     }
  770.     /*
  771.      * Notify all the descendants of this window that the world has changed.
  772.      *
  773.      * This could be done recursively or iteratively.  The recursive version
  774.      * is easier to implement and understand, and typically, windows with a
  775.      * -font option will be leaf nodes in the widget heirarchy (buttons,
  776.      * labels, etc.), so the recursion depth will be shallow.
  777.      *
  778.      * However, the additional overhead of the recursive calls may become
  779.      * a performance problem if typical usage alters such that -font'ed widgets
  780.      * appear high in the heirarchy, causing deep recursion.  This could happen
  781.      * with text widgets, or more likely with the (not yet existant) labeled
  782.      * frame widget.  With these widgets it is possible, even likely, that a
  783.      * -font'ed widget (text or labeled frame) will not be a leaf node, but
  784.      * will instead have many descendants.  If this is ever found to cause
  785.      * a performance problem, it may be worth investigating an iterative
  786.      * version of the code below.
  787.      */
  788.     for (winPtr = winPtr->childList; winPtr != NULL; winPtr = winPtr->nextPtr) {
  789. RecomputeWidgets(winPtr);
  790.     }
  791. }
  792. /*
  793.  *---------------------------------------------------------------------------
  794.  *
  795.  * CreateNamedFont --
  796.  *
  797.  * Create the specified named font with the given attributes in the
  798.  * named font table associated with the interp.  
  799.  *
  800.  * Results:
  801.  * Returns TCL_OK if the font was successfully created, or TCL_ERROR
  802.  * if the named font already existed.  If TCL_ERROR is returned, an
  803.  * error message is left in the interp's result.
  804.  *
  805.  * Side effects:
  806.  * Assume there used to exist a named font by the specified name, and
  807.  * that the named font had been deleted, but there were still some
  808.  * widgets using the named font at the time it was deleted.  If a
  809.  * new named font is created with the same name, all those widgets
  810.  * that were using the old named font will be redisplayed using
  811.  * the new named font's attributes.
  812.  *
  813.  *---------------------------------------------------------------------------
  814.  */
  815. static int
  816. CreateNamedFont(interp, tkwin, name, faPtr)
  817.     Tcl_Interp *interp; /* Interp for error return. */
  818.     Tk_Window tkwin; /* A window associated with interp. */
  819.     CONST char *name; /* Name for the new named font. */
  820.     TkFontAttributes *faPtr; /* Attributes for the new named font. */
  821. {
  822.     TkFontInfo *fiPtr;
  823.     Tcl_HashEntry *namedHashPtr;
  824.     int new;
  825.     NamedFont *nfPtr;    
  826.     fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
  827.     namedHashPtr = Tcl_CreateHashEntry(&fiPtr->namedTable, name, &new);
  828.     
  829.     if (new == 0) {
  830. nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
  831. if (nfPtr->deletePending == 0) {
  832.     Tcl_ResetResult(interp);
  833.     Tcl_AppendResult(interp, "named font "", name,
  834.     "" already exists", (char *) NULL);
  835.     return TCL_ERROR;
  836. }
  837. /*
  838.  * Recreating a named font with the same name as a previous
  839.  * named font.  Some widgets were still using that named
  840.  * font, so they need to get redisplayed.
  841.  */
  842. nfPtr->fa = *faPtr;
  843. nfPtr->deletePending = 0;
  844. UpdateDependentFonts(fiPtr, tkwin, namedHashPtr);
  845. return TCL_OK;
  846.     }
  847.     nfPtr = (NamedFont *) ckalloc(sizeof(NamedFont));
  848.     nfPtr->deletePending = 0;
  849.     Tcl_SetHashValue(namedHashPtr, nfPtr);
  850.     nfPtr->fa = *faPtr;
  851.     nfPtr->refCount = 0;
  852.     nfPtr->deletePending = 0;
  853.     return TCL_OK;
  854. }
  855. /*
  856.  *---------------------------------------------------------------------------
  857.  *
  858.  * Tk_GetFont -- 
  859.  *
  860.  * Given a string description of a font, map the description to a
  861.  * corresponding Tk_Font that represents the font.
  862.  *
  863.  * Results:
  864.  * The return value is token for the font, or NULL if an error
  865.  * prevented the font from being created.  If NULL is returned, an
  866.  * error message will be left in the interp's result.
  867.  *
  868.  * Side effects:
  869.  * The font is added to an internal database with a reference
  870.  * count.  For each call to this procedure, there should eventually
  871.  * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the
  872.  * database is cleaned up when fonts aren't in use anymore.
  873.  *
  874.  *---------------------------------------------------------------------------
  875.  */
  876. Tk_Font
  877. Tk_GetFont(interp, tkwin, string)
  878.     Tcl_Interp *interp; /* Interp for database and error return, or
  879.  * NULL for no error messages. */
  880.     Tk_Window tkwin; /* For display on which font will be used. */
  881.     CONST char *string; /* String describing font, as: named font,
  882.  * native format, or parseable string. */
  883. {
  884.     Tk_Font tkfont; 
  885.     Tcl_Obj *strPtr;
  886.     strPtr = Tcl_NewStringObj((char *) string, -1);
  887.     Tcl_IncrRefCount(strPtr);
  888.     tkfont = Tk_AllocFontFromObj(interp, tkwin, strPtr);
  889.     Tcl_DecrRefCount(strPtr);
  890.     return tkfont;
  891. }
  892. /*
  893.  *---------------------------------------------------------------------------
  894.  *
  895.  * Tk_AllocFontFromObj -- 
  896.  *
  897.  * Given a string description of a font, map the description to a
  898.  * corresponding Tk_Font that represents the font.
  899.  *
  900.  * Results:
  901.  * The return value is token for the font, or NULL if an error
  902.  * prevented the font from being created.  If NULL is returned, an
  903.  * error message will be left in interp's result object (if non-NULL).
  904.  *
  905.  * Side effects:
  906.  *  The font is added to an internal database with a reference
  907.  * count.  For each call to this procedure, there should eventually
  908.  * be a call to Tk_FreeFont() or Tk_FreeFontFromObj() so that the
  909.  * database is cleaned up when fonts aren't in use anymore.
  910.  *
  911.  *---------------------------------------------------------------------------
  912.  */
  913. Tk_Font
  914. Tk_AllocFontFromObj(interp, tkwin, objPtr)
  915.     Tcl_Interp *interp; /* Interp for database and error return. */
  916.     Tk_Window tkwin; /* For screen on which font will be used. */
  917.     Tcl_Obj *objPtr; /* Object describing font, as: named font,
  918.  * native format, or parseable string. */
  919. {
  920.     TkFontInfo *fiPtr;
  921.     Tcl_HashEntry *cacheHashPtr, *namedHashPtr;
  922.     TkFont *fontPtr, *firstFontPtr, *oldFontPtr;
  923.     int new, descent;
  924.     NamedFont *nfPtr;
  925.     fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
  926.     if (objPtr->typePtr != &tkFontObjType) {
  927. SetFontFromAny(interp, objPtr);
  928.     }
  929.     oldFontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
  930.     if (oldFontPtr != NULL) {
  931. if (oldFontPtr->resourceRefCount == 0) {
  932.     /*
  933.      * This is a stale reference: it refers to a TkFont that's
  934.      * no longer in use.  Clear the reference.
  935.      */
  936.     FreeFontObjProc(objPtr);
  937.     oldFontPtr = NULL;
  938. } else if (Tk_Screen(tkwin) == oldFontPtr->screen) {
  939.     oldFontPtr->resourceRefCount++;
  940.     return (Tk_Font) oldFontPtr;
  941. }
  942.     }
  943.     /*
  944.      * Next, search the list of fonts that have the name we want, to see
  945.      * if one of them is for the right screen.
  946.      */
  947.     new = 0;
  948.     if (oldFontPtr != NULL) {
  949. cacheHashPtr = oldFontPtr->cacheHashPtr;
  950. FreeFontObjProc(objPtr);
  951.     } else {
  952. cacheHashPtr = Tcl_CreateHashEntry(&fiPtr->fontCache,
  953. Tcl_GetString(objPtr), &new);
  954.     }
  955.     firstFontPtr = (TkFont *) Tcl_GetHashValue(cacheHashPtr);
  956.     for (fontPtr = firstFontPtr; (fontPtr != NULL);
  957.     fontPtr = fontPtr->nextPtr) {
  958. if (Tk_Screen(tkwin) == fontPtr->screen) {
  959.     fontPtr->resourceRefCount++;
  960.     fontPtr->objRefCount++;
  961.     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
  962.     return (Tk_Font) fontPtr;
  963. }
  964.     }
  965.     /*
  966.      * The desired font isn't in the table.  Make a new one.
  967.      */
  968.     namedHashPtr = Tcl_FindHashEntry(&fiPtr->namedTable,
  969.     Tcl_GetString(objPtr));
  970.     if (namedHashPtr != NULL) {
  971. /*
  972.  * Construct a font based on a named font.
  973.  */
  974. nfPtr = (NamedFont *) Tcl_GetHashValue(namedHashPtr);
  975. nfPtr->refCount++;
  976. fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &nfPtr->fa);
  977.     } else {
  978. /*
  979.  * Native font?
  980.  */
  981. fontPtr = TkpGetNativeFont(tkwin, Tcl_GetString(objPtr));
  982. if (fontPtr == NULL) {
  983.     TkFontAttributes fa;
  984.     Tcl_Obj *dupObjPtr = Tcl_DuplicateObj(objPtr);
  985.     if (ParseFontNameObj(interp, tkwin, dupObjPtr, &fa) != TCL_OK) {
  986. if (new) {
  987.     Tcl_DeleteHashEntry(cacheHashPtr);
  988. }
  989. Tcl_DecrRefCount(dupObjPtr);
  990. return NULL;
  991.     }
  992.     Tcl_DecrRefCount(dupObjPtr);
  993.     /*
  994.      * String contained the attributes inline.
  995.      */
  996.     fontPtr = TkpGetFontFromAttributes(NULL, tkwin, &fa);
  997. }
  998.     }
  999.     fontPtr->resourceRefCount = 1;
  1000.     fontPtr->objRefCount = 1;
  1001.     fontPtr->cacheHashPtr = cacheHashPtr;
  1002.     fontPtr->namedHashPtr = namedHashPtr;
  1003.     fontPtr->screen = Tk_Screen(tkwin);
  1004.     fontPtr->nextPtr = firstFontPtr;
  1005.     Tcl_SetHashValue(cacheHashPtr, fontPtr);
  1006.     Tk_MeasureChars((Tk_Font) fontPtr, "0", 1, -1, 0, &fontPtr->tabWidth);
  1007.     if (fontPtr->tabWidth == 0) {
  1008. fontPtr->tabWidth = fontPtr->fm.maxWidth;
  1009.     }
  1010.     fontPtr->tabWidth *= 8;
  1011.     /*
  1012.      * Make sure the tab width isn't zero (some fonts may not have enough
  1013.      * information to set a reasonable tab width).
  1014.      */
  1015.     if (fontPtr->tabWidth == 0) {
  1016. fontPtr->tabWidth = 1;
  1017.     }
  1018.     /*
  1019.      * Get information used for drawing underlines in generic code on a
  1020.      * non-underlined font.
  1021.      */
  1022.     
  1023.     descent = fontPtr->fm.descent;
  1024.     fontPtr->underlinePos = descent / 2;
  1025.     fontPtr->underlineHeight = TkFontGetPixels(tkwin, fontPtr->fa.size) / 10;
  1026.     if (fontPtr->underlineHeight == 0) {
  1027. fontPtr->underlineHeight = 1;
  1028.     }
  1029.     if (fontPtr->underlinePos + fontPtr->underlineHeight > descent) {
  1030. /*
  1031.  * If this set of values would cause the bottom of the underline
  1032.  * bar to stick below the descent of the font, jack the underline
  1033.  * up a bit higher.
  1034.  */
  1035. fontPtr->underlineHeight = descent - fontPtr->underlinePos;
  1036. if (fontPtr->underlineHeight == 0) {
  1037.     fontPtr->underlinePos--;
  1038.     fontPtr->underlineHeight = 1;
  1039. }
  1040.     }
  1041.     
  1042.     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
  1043.     return (Tk_Font) fontPtr;
  1044. }
  1045. /*
  1046.  *----------------------------------------------------------------------
  1047.  *
  1048.  * Tk_GetFontFromObj --
  1049.  *
  1050.  * Find the font that corresponds to a given object.  The font must
  1051.  * have already been created by Tk_GetFont or Tk_AllocFontFromObj.
  1052.  *
  1053.  * Results:
  1054.  * The return value is a token for the font that matches objPtr
  1055.  * and is suitable for use in tkwin.
  1056.  *
  1057.  * Side effects:
  1058.  * If the object is not already a font ref, the conversion will free
  1059.  * any old internal representation. 
  1060.  *
  1061.  *----------------------------------------------------------------------
  1062.  */
  1063. Tk_Font
  1064. Tk_GetFontFromObj(tkwin, objPtr)
  1065.     Tk_Window tkwin; /* The window that the font will be used in. */
  1066.     Tcl_Obj *objPtr; /* The object from which to get the font. */
  1067. {
  1068.     TkFontInfo *fiPtr = ((TkWindow *) tkwin)->mainPtr->fontInfoPtr;
  1069.     TkFont *fontPtr;
  1070.     Tcl_HashEntry *hashPtr;
  1071.  
  1072.     if (objPtr->typePtr != &tkFontObjType) {
  1073. SetFontFromAny((Tcl_Interp *) NULL, objPtr);
  1074.     }
  1075.     fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
  1076.     if (fontPtr != NULL) {
  1077. if (fontPtr->resourceRefCount == 0) {
  1078.     /*
  1079.      * This is a stale reference: it refers to a TkFont that's
  1080.      * no longer in use.  Clear the reference.
  1081.      */
  1082.     FreeFontObjProc(objPtr);
  1083.     fontPtr = NULL;
  1084. } else if (Tk_Screen(tkwin) == fontPtr->screen) {
  1085.     return (Tk_Font) fontPtr;
  1086. }
  1087.     }
  1088.     /*
  1089.      * Next, search the list of fonts that have the name we want, to see
  1090.      * if one of them is for the right screen.
  1091.      */
  1092.     if (fontPtr != NULL) {
  1093. hashPtr = fontPtr->cacheHashPtr;
  1094. FreeFontObjProc(objPtr);
  1095.     } else {
  1096. hashPtr = Tcl_FindHashEntry(&fiPtr->fontCache, Tcl_GetString(objPtr));
  1097.     }
  1098.     if (hashPtr != NULL) {
  1099. for (fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr); fontPtr != NULL;
  1100. fontPtr = fontPtr->nextPtr) {
  1101.     if (Tk_Screen(tkwin) == fontPtr->screen) {
  1102. fontPtr->objRefCount++;
  1103. objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
  1104. return (Tk_Font) fontPtr;
  1105.     }
  1106. }
  1107.     }
  1108.     panic("Tk_GetFontFromObj called with non-existent font!");
  1109.     return NULL;
  1110. }
  1111. /*
  1112.  *----------------------------------------------------------------------
  1113.  *
  1114.  * SetFontFromAny --
  1115.  *
  1116.  * Convert the internal representation of a Tcl object to the
  1117.  * font internal form.
  1118.  *
  1119.  * Results:
  1120.  * Always returns TCL_OK.
  1121.  *
  1122.  * Side effects:
  1123.  * The object is left with its typePtr pointing to tkFontObjType.
  1124.  * The TkFont pointer is NULL.
  1125.  *
  1126.  *----------------------------------------------------------------------
  1127.  */
  1128. static int
  1129. SetFontFromAny(interp, objPtr)
  1130.     Tcl_Interp *interp; /* Used for error reporting if not NULL. */
  1131.     Tcl_Obj *objPtr; /* The object to convert. */
  1132. {
  1133.     Tcl_ObjType *typePtr;
  1134.     /*
  1135.      * Free the old internalRep before setting the new one. 
  1136.      */
  1137.     Tcl_GetString(objPtr);
  1138.     typePtr = objPtr->typePtr;
  1139.     if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
  1140. (*typePtr->freeIntRepProc)(objPtr);
  1141.     }
  1142.     objPtr->typePtr = &tkFontObjType;
  1143.     objPtr->internalRep.twoPtrValue.ptr1 = NULL;
  1144.     return TCL_OK;
  1145. }
  1146. /*
  1147.  *---------------------------------------------------------------------------
  1148.  *
  1149.  * Tk_NameOfFont --
  1150.  *
  1151.  * Given a font, return a textual string identifying it.
  1152.  *
  1153.  * Results:
  1154.  * The return value is the description that was passed to
  1155.  * Tk_GetFont() to create the font.  The storage for the returned
  1156.  * string is only guaranteed to persist until the font is deleted.
  1157.  * The caller should not modify this string.
  1158.  *
  1159.  * Side effects:
  1160.  * None.
  1161.  *
  1162.  *---------------------------------------------------------------------------
  1163.  */
  1164. CONST char *
  1165. Tk_NameOfFont(tkfont)
  1166.     Tk_Font tkfont; /* Font whose name is desired. */
  1167. {
  1168.     TkFont *fontPtr;
  1169.     fontPtr = (TkFont *) tkfont;
  1170.     return fontPtr->cacheHashPtr->key.string;
  1171. }
  1172. /*
  1173.  *---------------------------------------------------------------------------
  1174.  *
  1175.  * Tk_FreeFont -- 
  1176.  *
  1177.  * Called to release a font allocated by Tk_GetFont().
  1178.  *
  1179.  * Results:
  1180.  * None.
  1181.  *
  1182.  * Side effects:
  1183.  * The reference count associated with font is decremented, and
  1184.  * only deallocated when no one is using it.
  1185.  *
  1186.  *---------------------------------------------------------------------------
  1187.  */
  1188. void
  1189. Tk_FreeFont(tkfont)
  1190.     Tk_Font tkfont; /* Font to be released. */
  1191. {
  1192.     TkFont *fontPtr, *prevPtr;
  1193.     NamedFont *nfPtr;
  1194.     if (tkfont == NULL) {
  1195. return;
  1196.     }
  1197.     fontPtr = (TkFont *) tkfont;
  1198.     fontPtr->resourceRefCount--;
  1199.     if (fontPtr->resourceRefCount > 0) {
  1200. return;
  1201.     }
  1202.     if (fontPtr->namedHashPtr != NULL) {
  1203. /*
  1204.  * This font derived from a named font.  Reduce the reference
  1205.  * count on the named font and free it if no-one else is
  1206.  * using it.
  1207.  */
  1208. nfPtr = (NamedFont *) Tcl_GetHashValue(fontPtr->namedHashPtr);
  1209. nfPtr->refCount--;
  1210. if ((nfPtr->refCount == 0) && (nfPtr->deletePending != 0)) {
  1211.     Tcl_DeleteHashEntry(fontPtr->namedHashPtr);
  1212.     ckfree((char *) nfPtr);
  1213. }
  1214.     }
  1215.     prevPtr = (TkFont *) Tcl_GetHashValue(fontPtr->cacheHashPtr);
  1216.     if (prevPtr == fontPtr) {
  1217. if (fontPtr->nextPtr == NULL) {
  1218.     Tcl_DeleteHashEntry(fontPtr->cacheHashPtr);
  1219. } else  {
  1220.     Tcl_SetHashValue(fontPtr->cacheHashPtr, fontPtr->nextPtr);
  1221. }
  1222.     } else {
  1223. while (prevPtr->nextPtr != fontPtr) {
  1224.     prevPtr = prevPtr->nextPtr;
  1225. }
  1226. prevPtr->nextPtr = fontPtr->nextPtr;
  1227.     }
  1228.     TkpDeleteFont(fontPtr);
  1229.     if (fontPtr->objRefCount == 0) {
  1230. ckfree((char *) fontPtr);
  1231.     }
  1232. }
  1233. /*
  1234.  *---------------------------------------------------------------------------
  1235.  *
  1236.  * Tk_FreeFontFromObj -- 
  1237.  *
  1238.  * Called to release a font inside a Tcl_Obj *. Decrements the refCount
  1239.  * of the font and removes it from the hash tables if necessary.
  1240.  *
  1241.  * Results:
  1242.  * None.
  1243.  *
  1244.  * Side effects:
  1245.  * The reference count associated with font is decremented, and
  1246.  * only deallocated when no one is using it.
  1247.  *
  1248.  *---------------------------------------------------------------------------
  1249.  */
  1250. void
  1251. Tk_FreeFontFromObj(tkwin, objPtr)
  1252.     Tk_Window tkwin; /* The window this font lives in. Needed
  1253.  * for the screen value. */
  1254.     Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */
  1255. {
  1256.     Tk_FreeFont(Tk_GetFontFromObj(tkwin, objPtr));
  1257. }
  1258. /*
  1259.  *---------------------------------------------------------------------------
  1260.  *
  1261.  * FreeFontObjProc -- 
  1262.  *
  1263.  * This proc is called to release an object reference to a font.
  1264.  * Called when the object's internal rep is released or when
  1265.  * the cached fontPtr needs to be changed.
  1266.  *
  1267.  * Results:
  1268.  * None.
  1269.  *
  1270.  * Side effects:
  1271.  * The object reference count is decremented. When both it
  1272.  * and the hash ref count go to zero, the font's resources
  1273.  * are released.
  1274.  *
  1275.  *---------------------------------------------------------------------------
  1276.  */
  1277. static void
  1278. FreeFontObjProc(objPtr)
  1279.     Tcl_Obj *objPtr; /* The object we are releasing. */
  1280. {
  1281.     TkFont *fontPtr = (TkFont *) objPtr->internalRep.twoPtrValue.ptr1;
  1282.     if (fontPtr != NULL) {
  1283. fontPtr->objRefCount--;
  1284. if ((fontPtr->resourceRefCount == 0) && (fontPtr->objRefCount == 0)) {
  1285.     ckfree((char *) fontPtr);
  1286.     objPtr->internalRep.twoPtrValue.ptr1 = NULL;
  1287. }
  1288.     }
  1289. }
  1290. /*
  1291.  *---------------------------------------------------------------------------
  1292.  *
  1293.  * DupFontObjProc -- 
  1294.  *
  1295.  * When a cached font object is duplicated, this is called to
  1296.  * update the internal reps.
  1297.  *
  1298.  * Results:
  1299.  * None.
  1300.  *
  1301.  * Side effects:
  1302.  * The font's objRefCount is incremented and the internal rep
  1303.  * of the copy is set to point to it.
  1304.  *
  1305.  *---------------------------------------------------------------------------
  1306.  */
  1307. static void
  1308. DupFontObjProc(srcObjPtr, dupObjPtr)
  1309.     Tcl_Obj *srcObjPtr; /* The object we are copying from. */
  1310.     Tcl_Obj *dupObjPtr; /* The object we are copying to. */
  1311. {
  1312.     TkFont *fontPtr = (TkFont *) srcObjPtr->internalRep.twoPtrValue.ptr1;
  1313.     
  1314.     dupObjPtr->typePtr = srcObjPtr->typePtr;
  1315.     dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) fontPtr;
  1316.     if (fontPtr != NULL) {
  1317. fontPtr->objRefCount++;
  1318.     }
  1319. }
  1320. /*
  1321.  *---------------------------------------------------------------------------
  1322.  *
  1323.  * Tk_FontId --
  1324.  *
  1325.  * Given a font, return an opaque handle that should be selected
  1326.  * into the XGCValues structure in order to get the constructed
  1327.  * gc to use this font.  This procedure would go away if the
  1328.  * XGCValues structure were replaced with a TkGCValues structure.
  1329.  *
  1330.  * Results:
  1331.  * As above.
  1332.  *
  1333.  * Side effects:
  1334.  * None.
  1335.  *
  1336.  *---------------------------------------------------------------------------
  1337.  */
  1338. Font
  1339. Tk_FontId(tkfont)
  1340.     Tk_Font tkfont; /* Font that is going to be selected into GC. */
  1341. {
  1342.     TkFont *fontPtr;
  1343.     fontPtr = (TkFont *) tkfont;
  1344.     return fontPtr->fid;
  1345. }
  1346. /*
  1347.  *---------------------------------------------------------------------------
  1348.  *
  1349.  * Tk_GetFontMetrics --
  1350.  *
  1351.  * Returns overall ascent and descent metrics for the given font.
  1352.  * These values can be used to space multiple lines of text and
  1353.  * to align the baselines of text in different fonts.
  1354.  *
  1355.  * Results:
  1356.  * If *heightPtr is non-NULL, it is filled with the overall height
  1357.  * of the font, which is the sum of the ascent and descent.
  1358.  * If *ascentPtr or *descentPtr is non-NULL, they are filled with
  1359.  * the ascent and/or descent information for the font.
  1360.  *
  1361.  * Side effects:
  1362.  * None.
  1363.  *
  1364.  *---------------------------------------------------------------------------
  1365.  */
  1366. void
  1367. Tk_GetFontMetrics(tkfont, fmPtr)
  1368.     Tk_Font tkfont; /* Font in which metrics are calculated. */
  1369.     Tk_FontMetrics *fmPtr; /* Pointer to structure in which font
  1370.  * metrics for tkfont will be stored. */
  1371. {
  1372.     TkFont *fontPtr;
  1373.     fontPtr = (TkFont *) tkfont;
  1374.     fmPtr->ascent = fontPtr->fm.ascent;
  1375.     fmPtr->descent = fontPtr->fm.descent;
  1376.     fmPtr->linespace = fontPtr->fm.ascent + fontPtr->fm.descent;
  1377. }
  1378. /*
  1379.  *---------------------------------------------------------------------------
  1380.  *
  1381.  * Tk_PostscriptFontName --
  1382.  *
  1383.  * Given a Tk_Font, return the name of the corresponding Postscript
  1384.  * font.
  1385.  *
  1386.  * Results:
  1387.  * The return value is the pointsize of the given Tk_Font.
  1388.  * The name of the Postscript font is appended to dsPtr.
  1389.  *
  1390.  * Side effects:
  1391.  * If the font does not exist on the printer, the print job will
  1392.  * fail at print time.  Given a "reasonable" Postscript printer,
  1393.  * the following Tk_Font font families should print correctly:
  1394.  *
  1395.  *     Avant Garde, Arial, Bookman, Courier, Courier New, Geneva,
  1396.  *     Helvetica, Monaco, New Century Schoolbook, New York,
  1397.  *     Palatino, Symbol, Times, Times New Roman, Zapf Chancery,
  1398.  *     and Zapf Dingbats.
  1399.  *
  1400.  * Any other Tk_Font font families may not print correctly
  1401.  * because the computed Postscript font name may be incorrect.
  1402.  *
  1403.  *---------------------------------------------------------------------------
  1404.  */
  1405. int
  1406. Tk_PostscriptFontName(tkfont, dsPtr)
  1407.     Tk_Font tkfont; /* Font in which text will be printed. */
  1408.     Tcl_DString *dsPtr; /* Pointer to an initialized Tcl_DString to
  1409.  * which the name of the Postscript font that
  1410.  * corresponds to tkfont will be appended. */
  1411. {
  1412.     TkFont *fontPtr;
  1413.     Tk_Uid family, weightString, slantString;
  1414.     char *src, *dest;
  1415.     int upper, len;
  1416.     len = Tcl_DStringLength(dsPtr);
  1417.     fontPtr = (TkFont *) tkfont;
  1418.     /*
  1419.      * Convert the case-insensitive Tk_Font family name to the
  1420.      * case-sensitive Postscript family name.  Take out any spaces and
  1421.      * capitalize the first letter of each word.
  1422.      */
  1423.     family = fontPtr->fa.family;
  1424.     if (strncasecmp(family, "itc ", 4) == 0) {
  1425. family = family + 4;
  1426.     }
  1427.     if ((strcasecmp(family, "Arial") == 0)
  1428.     || (strcasecmp(family, "Geneva") == 0)) {
  1429. family = "Helvetica";
  1430.     } else if ((strcasecmp(family, "Times New Roman") == 0)
  1431.     || (strcasecmp(family, "New York") == 0)) {
  1432. family = "Times";
  1433.     } else if ((strcasecmp(family, "Courier New") == 0)
  1434.     || (strcasecmp(family, "Monaco") == 0)) {
  1435. family = "Courier";
  1436.     } else if (strcasecmp(family, "AvantGarde") == 0) {
  1437. family = "AvantGarde";
  1438.     } else if (strcasecmp(family, "ZapfChancery") == 0) {
  1439. family = "ZapfChancery";
  1440.     } else if (strcasecmp(family, "ZapfDingbats") == 0) {
  1441. family = "ZapfDingbats";
  1442.     } else {
  1443. Tcl_UniChar ch;
  1444. /*
  1445.  * Inline, capitalize the first letter of each word, lowercase the
  1446.  * rest of the letters in each word, and then take out the spaces
  1447.  * between the words.  This may make the DString shorter, which is
  1448.  * safe to do.
  1449.  */
  1450. Tcl_DStringAppend(dsPtr, family, -1);
  1451. src = dest = Tcl_DStringValue(dsPtr) + len;
  1452. upper = 1;
  1453. for (; *src != ''; ) {
  1454.     while (isspace(UCHAR(*src))) { /* INTL: ISO space */
  1455. src++;
  1456. upper = 1;
  1457.     }
  1458.     src += Tcl_UtfToUniChar(src, &ch);
  1459.     if (upper) {
  1460. ch = Tcl_UniCharToUpper(ch);
  1461. upper = 0;
  1462.     } else {
  1463.         ch = Tcl_UniCharToLower(ch);
  1464.     }
  1465.     dest += Tcl_UniCharToUtf(ch, dest);
  1466. }
  1467. *dest = '';
  1468. Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr));
  1469. family = Tcl_DStringValue(dsPtr) + len;
  1470.     }
  1471.     if (family != Tcl_DStringValue(dsPtr) + len) {
  1472. Tcl_DStringAppend(dsPtr, family, -1);
  1473. family = Tcl_DStringValue(dsPtr) + len;
  1474.     }
  1475.     if (strcasecmp(family, "NewCenturySchoolbook") == 0) {
  1476. Tcl_DStringSetLength(dsPtr, len);
  1477. Tcl_DStringAppend(dsPtr, "NewCenturySchlbk", -1);
  1478. family = Tcl_DStringValue(dsPtr) + len;
  1479.     }
  1480.     /*
  1481.      * Get the string to use for the weight.
  1482.      */
  1483.     weightString = NULL;
  1484.     if (fontPtr->fa.weight == TK_FW_NORMAL) {
  1485. if (strcmp(family, "Bookman") == 0) {
  1486.     weightString = "Light";
  1487. } else if (strcmp(family, "AvantGarde") == 0) {
  1488.     weightString = "Book";
  1489. } else if (strcmp(family, "ZapfChancery") == 0) {
  1490.     weightString = "Medium";
  1491. }
  1492.     } else {
  1493. if ((strcmp(family, "Bookman") == 0)
  1494. || (strcmp(family, "AvantGarde") == 0)) {
  1495.     weightString = "Demi";
  1496. } else {
  1497.     weightString = "Bold";
  1498. }
  1499.     }
  1500.     /*
  1501.      * Get the string to use for the slant.
  1502.      */
  1503.     slantString = NULL;
  1504.     if (fontPtr->fa.slant == TK_FS_ROMAN) {
  1505. ;
  1506.     } else {
  1507. if ((strcmp(family, "Helvetica") == 0)
  1508. || (strcmp(family, "Courier") == 0)
  1509. || (strcmp(family, "AvantGarde") == 0)) {
  1510.     slantString = "Oblique";
  1511. } else {
  1512.     slantString = "Italic";
  1513. }
  1514.     }
  1515.     /*
  1516.      * The string "Roman" needs to be added to some fonts that are not bold
  1517.      * and not italic.
  1518.      */
  1519.     if ((slantString == NULL) && (weightString == NULL)) {
  1520. if ((strcmp(family, "Times") == 0) 
  1521. || (strcmp(family, "NewCenturySchlbk") == 0)
  1522. || (strcmp(family, "Palatino") == 0)) {
  1523.     Tcl_DStringAppend(dsPtr, "-Roman", -1);
  1524. }
  1525.     } else {
  1526. Tcl_DStringAppend(dsPtr, "-", -1);
  1527. if (weightString != NULL) {
  1528.     Tcl_DStringAppend(dsPtr, weightString, -1);
  1529. }
  1530. if (slantString != NULL) {
  1531.     Tcl_DStringAppend(dsPtr, slantString, -1);
  1532. }
  1533.     }
  1534.     return fontPtr->fa.size;
  1535. }
  1536. /*
  1537.  *---------------------------------------------------------------------------
  1538.  *
  1539.  * Tk_TextWidth --
  1540.  *
  1541.  * A wrapper function for the more complicated interface of
  1542.  * Tk_MeasureChars.  Computes how much space the given
  1543.  * simple string needs.
  1544.  *
  1545.  * Results:
  1546.  * The return value is the width (in pixels) of the given string.
  1547.  *
  1548.  * Side effects:
  1549.  * None.
  1550.  *
  1551.  *---------------------------------------------------------------------------
  1552.  */
  1553. int
  1554. Tk_TextWidth(tkfont, string, numBytes)
  1555.     Tk_Font tkfont; /* Font in which text will be measured. */
  1556.     CONST char *string; /* String whose width will be computed. */
  1557.     int numBytes; /* Number of bytes to consider from
  1558.  * string, or < 0 for strlen(). */
  1559. {
  1560.     int width;
  1561.     if (numBytes < 0) {
  1562. numBytes = strlen(string);
  1563.     }
  1564.     Tk_MeasureChars(tkfont, string, numBytes, -1, 0, &width);
  1565.     return width;
  1566. }
  1567. /*
  1568.  *---------------------------------------------------------------------------
  1569.  *
  1570.  * Tk_UnderlineChars --
  1571.  *
  1572.  * This procedure draws an underline for a given range of characters
  1573.  * in a given string.  It doesn't draw the characters (which are
  1574.  * assumed to have been displayed previously); it just draws the
  1575.  * underline.  This procedure would mainly be used to quickly
  1576.  * underline a few characters without having to construct an
  1577.  * underlined font.  To produce properly underlined text, the
  1578.  * appropriate underlined font should be constructed and used. 
  1579.  *
  1580.  * Results:
  1581.  * None.
  1582.  *
  1583.  * Side effects:
  1584.  * Information gets displayed in "drawable".
  1585.  *
  1586.  *----------------------------------------------------------------------
  1587.  */
  1588. void
  1589. Tk_UnderlineChars(display, drawable, gc, tkfont, string, x, y, firstByte,
  1590. lastByte)
  1591.     Display *display; /* Display on which to draw. */
  1592.     Drawable drawable; /* Window or pixmap in which to draw. */
  1593.     GC gc; /* Graphics context for actually drawing
  1594.  * line. */
  1595.     Tk_Font tkfont; /* Font used in GC;  must have been allocated
  1596.  * by Tk_GetFont().  Used for character
  1597.  * dimensions, etc. */
  1598.     CONST char *string; /* String containing characters to be
  1599.  * underlined or overstruck. */
  1600.     int x, y; /* Coordinates at which first character of
  1601.  * string is drawn. */
  1602.     int firstByte; /* Index of first byte of first character. */
  1603.     int lastByte; /* Index of first byte after the last
  1604.  * character. */
  1605. {
  1606.     TkFont *fontPtr;
  1607.     int startX, endX;
  1608.     fontPtr = (TkFont *) tkfont;
  1609.     
  1610.     Tk_MeasureChars(tkfont, string, firstByte, -1, 0, &startX);
  1611.     Tk_MeasureChars(tkfont, string, lastByte, -1, 0, &endX);
  1612.     XFillRectangle(display, drawable, gc, x + startX,
  1613.     y + fontPtr->underlinePos, (unsigned int) (endX - startX),
  1614.     (unsigned int) fontPtr->underlineHeight);
  1615. }
  1616. /*
  1617.  *---------------------------------------------------------------------------
  1618.  *
  1619.  * Tk_ComputeTextLayout --
  1620.  *
  1621.  * Computes the amount of screen space needed to display a
  1622.  * multi-line, justified string of text.  Records all the
  1623.  * measurements that were done to determine to size and
  1624.  * positioning of the individual lines of text; this information
  1625.  * can be used by the Tk_DrawTextLayout() procedure to
  1626.  * display the text quickly (without remeasuring it).
  1627.  *
  1628.  * This procedure is useful for simple widgets that want to
  1629.  * display single-font, multi-line text and want Tk to handle the
  1630.  * details.
  1631.  *
  1632.  * Results:
  1633.  * The return value is a Tk_TextLayout token that holds the
  1634.  * measurement information for the given string.  The token is
  1635.  * only valid for the given string.  If the string is freed,
  1636.  * the token is no longer valid and must also be freed.  To free
  1637.  * the token, call Tk_FreeTextLayout().
  1638.  *
  1639.  * The dimensions of the screen area needed to display the text
  1640.  * are stored in *widthPtr and *heightPtr.
  1641.  *
  1642.  * Side effects:
  1643.  * Memory is allocated to hold the measurement information.  
  1644.  *
  1645.  *---------------------------------------------------------------------------
  1646.  */
  1647. Tk_TextLayout
  1648. Tk_ComputeTextLayout(tkfont, string, numChars, wrapLength, justify, flags,
  1649. widthPtr, heightPtr)
  1650.     Tk_Font tkfont; /* Font that will be used to display text. */
  1651.     CONST char *string; /* String whose dimensions are to be
  1652.  * computed. */
  1653.     int numChars; /* Number of characters to consider from
  1654.  * string, or < 0 for strlen(). */
  1655.     int wrapLength; /* Longest permissible line length, in
  1656.  * pixels.  <= 0 means no automatic wrapping:
  1657.  * just let lines get as long as needed. */
  1658.     Tk_Justify justify; /* How to justify lines. */
  1659.     int flags; /* Flag bits OR-ed together.
  1660.  * TK_IGNORE_TABS means that tab characters
  1661.  * should not be expanded.  TK_IGNORE_NEWLINES
  1662.  * means that newline characters should not
  1663.  * cause a line break. */
  1664.     int *widthPtr; /* Filled with width of string. */
  1665.     int *heightPtr; /* Filled with height of string. */
  1666. {
  1667.     TkFont *fontPtr;
  1668.     CONST char *start, *end, *special;
  1669.     int n, y, bytesThisChunk, maxChunks;
  1670.     int baseline, height, curX, newX, maxWidth;
  1671.     TextLayout *layoutPtr;
  1672.     LayoutChunk *chunkPtr;
  1673.     CONST TkFontMetrics *fmPtr;
  1674.     Tcl_DString lineBuffer;
  1675.     int *lineLengths;
  1676.     int curLine, layoutHeight;
  1677.     Tcl_DStringInit(&lineBuffer);
  1678.     
  1679.     fontPtr = (TkFont *) tkfont;
  1680.     if ((fontPtr == NULL) || (string == NULL)) {
  1681. if (widthPtr != NULL) {
  1682.     *widthPtr = 0;
  1683. }
  1684. if (heightPtr != NULL) {
  1685.     *heightPtr = 0;
  1686. }
  1687. return NULL;
  1688.     }
  1689.     fmPtr = &fontPtr->fm;
  1690.     height = fmPtr->ascent + fmPtr->descent;
  1691.     if (numChars < 0) {
  1692. numChars = Tcl_NumUtfChars(string, -1);
  1693.     }
  1694.     if (wrapLength == 0) {
  1695. wrapLength = -1;
  1696.     }
  1697.     maxChunks = 1;
  1698.     layoutPtr = (TextLayout *) ckalloc(sizeof(TextLayout)
  1699.     + (maxChunks - 1) * sizeof(LayoutChunk));
  1700.     layoutPtr->tkfont     = tkfont;
  1701.     layoutPtr->string     = string;
  1702.     layoutPtr->numChunks    = 0;
  1703.     baseline = fmPtr->ascent;
  1704.     maxWidth = 0;
  1705.     /*
  1706.      * Divide the string up into simple strings and measure each string.
  1707.      */
  1708.     curX = 0;
  1709.     end = Tcl_UtfAtIndex(string, numChars);
  1710.     special = string;
  1711.     flags &= TK_IGNORE_TABS | TK_IGNORE_NEWLINES;
  1712.     flags |= TK_WHOLE_WORDS | TK_AT_LEAST_ONE;     
  1713.     for (start = string; start < end; ) {
  1714. if (start >= special) {
  1715.     /*
  1716.      * Find the next special character in the string.
  1717.      *
  1718.      * INTL: Note that it is safe to increment by byte, because we are
  1719.      * looking for 7-bit characters that will appear unchanged in
  1720.      * UTF-8.  At some point we may need to support the full Unicode
  1721.      * whitespace set.
  1722.      */
  1723.     for (special = start; special < end; special++) {
  1724. if (!(flags & TK_IGNORE_NEWLINES)) {
  1725.     if ((*special == 'n') || (*special == 'r')) {
  1726. break;
  1727.     }
  1728. }
  1729. if (!(flags & TK_IGNORE_TABS)) {
  1730.     if (*special == 't') {
  1731. break;
  1732.     }
  1733. }
  1734.     }
  1735. }
  1736. /*
  1737.  * Special points at the next special character (or the end of the
  1738.  * string).  Process characters between start and special.
  1739.  */
  1740. chunkPtr = NULL;
  1741. if (start < special) {
  1742.     bytesThisChunk = Tk_MeasureChars(tkfont, start, special - start,
  1743.     wrapLength - curX, flags, &newX);
  1744.     newX += curX;
  1745.     flags &= ~TK_AT_LEAST_ONE;
  1746.     if (bytesThisChunk > 0) {
  1747. chunkPtr = NewChunk(&layoutPtr, &maxChunks, start,
  1748. bytesThisChunk, curX, newX, baseline);
  1749. start += bytesThisChunk;
  1750. curX = newX;
  1751.     }
  1752. }
  1753. if ((start == special) && (special < end)) {
  1754.     /*
  1755.      * Handle the special character.
  1756.      *
  1757.      * INTL: Special will be pointing at a 7-bit character so we
  1758.      * can safely treat it as a single byte.
  1759.      */
  1760.     chunkPtr = NULL;
  1761.     if (*special == 't') {
  1762. newX = curX + fontPtr->tabWidth;
  1763. newX -= newX % fontPtr->tabWidth;
  1764. NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX,
  1765. baseline)->numDisplayChars = -1;
  1766. start++;
  1767. if ((start < end) &&
  1768. ((wrapLength <= 0) || (newX <= wrapLength))) {
  1769.     /*
  1770.      * More chars can still fit on this line.
  1771.      */
  1772.     curX = newX;
  1773.     flags &= ~TK_AT_LEAST_ONE;
  1774.     continue;
  1775. }
  1776.     } else {
  1777. NewChunk(&layoutPtr, &maxChunks, start, 1, curX, curX,
  1778. baseline)->numDisplayChars = -1;
  1779. start++;
  1780. goto wrapLine;
  1781.     }
  1782. }
  1783. /*
  1784.  * No more characters are going to go on this line, either because
  1785.  * no more characters can fit or there are no more characters left.
  1786.  * Consume all extra spaces at end of line.  
  1787.  */
  1788. while ((start < end) && isspace(UCHAR(*start))) { /* INTL: ISO space */
  1789.     if (!(flags & TK_IGNORE_NEWLINES)) {
  1790. if ((*start == 'n') || (*start == 'r')) {
  1791.     break;
  1792. }
  1793.     }
  1794.     if (!(flags & TK_IGNORE_TABS)) {
  1795. if (*start == 't') {
  1796.     break;
  1797. }
  1798.     }
  1799.     start++;
  1800. }
  1801. if (chunkPtr != NULL) {
  1802.     CONST char *end;
  1803.     /*
  1804.      * Append all the extra spaces on this line to the end of the
  1805.      * last text chunk.  This is a little tricky because we are
  1806.      * switching back and forth between characters and bytes.
  1807.      */
  1808.     end = chunkPtr->start + chunkPtr->numBytes;
  1809.     bytesThisChunk = start - end;
  1810.     if (bytesThisChunk > 0) {
  1811. bytesThisChunk = Tk_MeasureChars(tkfont, end, bytesThisChunk,
  1812. -1, 0, &chunkPtr->totalWidth);
  1813. chunkPtr->numBytes += bytesThisChunk;
  1814. chunkPtr->numChars += Tcl_NumUtfChars(end, bytesThisChunk);
  1815. chunkPtr->totalWidth += curX;
  1816.     }
  1817. }
  1818.         wrapLine: 
  1819. flags |= TK_AT_LEAST_ONE;
  1820. /*
  1821.  * Save current line length, then move current position to start of
  1822.  * next line.
  1823.  */
  1824. if (curX > maxWidth) {
  1825.     maxWidth = curX;
  1826. }
  1827. /*
  1828.  * Remember width of this line, so that all chunks on this line
  1829.  * can be centered or right justified, if necessary.
  1830.  */
  1831. Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));
  1832. curX = 0;
  1833. baseline += height;
  1834.     }
  1835.     /*
  1836.      * If last line ends with a newline, then we need to make a 0 width
  1837.      * chunk on the next line.  Otherwise "Hello" and "Hellon" are the
  1838.      * same height.
  1839.      */
  1840.     if ((layoutPtr->numChunks > 0) && ((flags & TK_IGNORE_NEWLINES) == 0)) {
  1841. if (layoutPtr->chunks[layoutPtr->numChunks - 1].start[0] == 'n') {
  1842.     chunkPtr = NewChunk(&layoutPtr, &maxChunks, start, 0, curX,
  1843.     curX, baseline);
  1844.     chunkPtr->numDisplayChars = -1;
  1845.     Tcl_DStringAppend(&lineBuffer, (char *) &curX, sizeof(curX));
  1846.     baseline += height;
  1847. }
  1848.     }     
  1849.     layoutPtr->width = maxWidth;
  1850.     layoutHeight = baseline - fmPtr->ascent;
  1851.     if (layoutPtr->numChunks == 0) {
  1852. layoutHeight = height;
  1853. /*
  1854.  * This fake chunk is used by the other procedures so that they can
  1855.  * pretend that there is a chunk with no chars in it, which makes
  1856.  * the coding simpler.
  1857.  */
  1858. layoutPtr->numChunks = 1;
  1859. layoutPtr->chunks[0].start = string;
  1860. layoutPtr->chunks[0].numBytes = 0;
  1861. layoutPtr->chunks[0].numChars = 0;
  1862. layoutPtr->chunks[0].numDisplayChars = -1;
  1863. layoutPtr->chunks[0].x = 0;
  1864. layoutPtr->chunks[0].y = fmPtr->ascent;
  1865. layoutPtr->chunks[0].totalWidth = 0;
  1866. layoutPtr->chunks[0].displayWidth = 0;
  1867.     } else {
  1868. /*
  1869.  * Using maximum line length, shift all the chunks so that the lines
  1870.  * are all justified correctly.
  1871.  */
  1872.     
  1873. curLine = 0;
  1874. chunkPtr = layoutPtr->chunks;
  1875. y = chunkPtr->y;
  1876. lineLengths = (int *) Tcl_DStringValue(&lineBuffer);
  1877. for (n = 0; n < layoutPtr->numChunks; n++) {
  1878.     int extra;
  1879.     if (chunkPtr->y != y) {
  1880. curLine++;
  1881. y = chunkPtr->y;
  1882.     }
  1883.     extra = maxWidth - lineLengths[curLine];
  1884.     if (justify == TK_JUSTIFY_CENTER) {
  1885. chunkPtr->x += extra / 2;
  1886.     } else if (justify == TK_JUSTIFY_RIGHT) {
  1887. chunkPtr->x += extra;
  1888.     }
  1889.     chunkPtr++;
  1890. }
  1891.     }
  1892.     if (widthPtr != NULL) {
  1893. *widthPtr = layoutPtr->width;
  1894.     }
  1895.     if (heightPtr != NULL) {
  1896. *heightPtr = layoutHeight;
  1897.     }
  1898.     Tcl_DStringFree(&lineBuffer);
  1899.     return (Tk_TextLayout) layoutPtr;
  1900. }
  1901. /*
  1902.  *---------------------------------------------------------------------------
  1903.  *
  1904.  * Tk_FreeTextLayout --
  1905.  *
  1906.  * This procedure is called to release the storage associated with
  1907.  * a Tk_TextLayout when it is no longer needed.
  1908.  *
  1909.  * Results:
  1910.  * None.
  1911.  *
  1912.  * Side effects:
  1913.  * Memory is freed.
  1914.  *
  1915.  *---------------------------------------------------------------------------
  1916.  */
  1917. void
  1918. Tk_FreeTextLayout(textLayout)
  1919.     Tk_TextLayout textLayout; /* The text layout to be released. */
  1920. {
  1921.     TextLayout *layoutPtr;
  1922.     layoutPtr = (TextLayout *) textLayout;
  1923.     if (layoutPtr != NULL) {
  1924. ckfree((char *) layoutPtr);
  1925.     }
  1926. }
  1927. /*
  1928.  *---------------------------------------------------------------------------
  1929.  *
  1930.  * Tk_DrawTextLayout --
  1931.  *
  1932.  * Use the information in the Tk_TextLayout token to display a
  1933.  * multi-line, justified string of text.
  1934.  *
  1935.  * This procedure is useful for simple widgets that need to
  1936.  * display single-font, multi-line text and want Tk to handle
  1937.  * the details.
  1938.  *
  1939.  * Results:
  1940.  * None.
  1941.  *
  1942.  * Side effects:
  1943.  * Text drawn on the screen.
  1944.  *
  1945.  *---------------------------------------------------------------------------
  1946.  */
  1947. void
  1948. Tk_DrawTextLayout(display, drawable, gc, layout, x, y, firstChar, lastChar)
  1949.     Display *display; /* Display on which to draw. */
  1950.     Drawable drawable; /* Window or pixmap in which to draw. */
  1951.     GC gc; /* Graphics context to use for drawing text. */
  1952.     Tk_TextLayout layout; /* Layout information, from a previous call
  1953.  * to Tk_ComputeTextLayout(). */
  1954.     int x, y; /* Upper-left hand corner of rectangle in
  1955.  * which to draw (pixels). */
  1956.     int firstChar; /* The index of the first character to draw
  1957.  * from the given text item.  0 specfies the
  1958.  * beginning. */
  1959.     int lastChar; /* The index just after the last character
  1960.  * to draw from the given text item.  A number
  1961.  * < 0 means to draw all characters. */
  1962. {
  1963.     TextLayout *layoutPtr;
  1964.     int i, numDisplayChars, drawX;
  1965.     CONST char *firstByte;
  1966.     CONST char *lastByte;
  1967.     LayoutChunk *chunkPtr;
  1968.     layoutPtr = (TextLayout *) layout;
  1969.     if (layoutPtr == NULL) {
  1970. return;
  1971.     }
  1972.     if (lastChar < 0) {
  1973. lastChar = 100000000;
  1974.     }
  1975.     chunkPtr = layoutPtr->chunks;
  1976.     for (i = 0; i < layoutPtr->numChunks; i++) {
  1977. numDisplayChars = chunkPtr->numDisplayChars;
  1978. if ((numDisplayChars > 0) && (firstChar < numDisplayChars)) {
  1979.     if (firstChar <= 0) {
  1980. drawX = 0;
  1981. firstChar = 0;
  1982. firstByte = chunkPtr->start;
  1983.     } else {
  1984. firstByte = Tcl_UtfAtIndex(chunkPtr->start, firstChar);
  1985. Tk_MeasureChars(layoutPtr->tkfont, chunkPtr->start,
  1986. firstByte - chunkPtr->start, -1, 0, &drawX);
  1987.     }
  1988.     if (lastChar < numDisplayChars) {
  1989. numDisplayChars = lastChar;
  1990.     }
  1991.     lastByte = Tcl_UtfAtIndex(chunkPtr->start, numDisplayChars);
  1992.     Tk_DrawChars(display, drawable, gc, layoutPtr->tkfont,
  1993.     firstByte, lastByte - firstByte,
  1994.     x + chunkPtr->x + drawX, y + chunkPtr->y);
  1995. }
  1996. firstChar -= chunkPtr->numChars;
  1997. lastChar -= chunkPtr->numChars;
  1998. if (lastChar <= 0) {
  1999.     break;
  2000. }
  2001. chunkPtr++;
  2002.     }
  2003. }
  2004. /*
  2005.  *---------------------------------------------------------------------------
  2006.  *
  2007.  * Tk_UnderlineTextLayout --
  2008.  *
  2009.  * Use the information in the Tk_TextLayout token to display an
  2010.  * underline below an individual character.  This procedure does
  2011.  * not draw the text, just the underline.
  2012.  *
  2013.  * This procedure is useful for simple widgets that need to
  2014.  * display single-font, multi-line text with an individual
  2015.  * character underlined and want Tk to handle the details.
  2016.  * To display larger amounts of underlined text, construct
  2017.  * and use an underlined font.
  2018.  *
  2019.  * Results:
  2020.  * None.
  2021.  *
  2022.  * Side effects:
  2023.  * Underline drawn on the screen.
  2024.  *
  2025.  *---------------------------------------------------------------------------
  2026.  */
  2027. void
  2028. Tk_UnderlineTextLayout(display, drawable, gc, layout, x, y, underline)
  2029.     Display *display; /* Display on which to draw. */
  2030.     Drawable drawable; /* Window or pixmap in which to draw. */
  2031.     GC gc; /* Graphics context to use for drawing text. */
  2032.     Tk_TextLayout layout; /* Layout information, from a previous call
  2033.  * to Tk_ComputeTextLayout(). */
  2034.     int x, y; /* Upper-left hand corner of rectangle in
  2035.  * which to draw (pixels). */
  2036.     int underline; /* Index of the single character to
  2037.  * underline, or -1 for no underline. */
  2038. {
  2039.     TextLayout *layoutPtr;
  2040.     TkFont *fontPtr;
  2041.     int xx, yy, width, height;
  2042.     if ((Tk_CharBbox(layout, underline, &xx, &yy, &width, &height) != 0)
  2043.     && (width != 0)) {
  2044. layoutPtr = (TextLayout *) layout;
  2045. fontPtr = (TkFont *) layoutPtr->tkfont;
  2046. XFillRectangle(display, drawable, gc, x + xx, 
  2047. y + yy + fontPtr->fm.ascent + fontPtr->underlinePos,
  2048. (unsigned int) width, (unsigned int) fontPtr->underlineHeight);
  2049.     }
  2050. }
  2051. /*
  2052.  *---------------------------------------------------------------------------
  2053.  *
  2054.  * Tk_PointToChar --
  2055.  *
  2056.  * Use the information in the Tk_TextLayout token to determine the
  2057.  * character closest to the given point.  The point must be
  2058.  * specified with respect to the upper-left hand corner of the
  2059.  * text layout, which is considered to be located at (0, 0).
  2060.  *
  2061.  * Any point whose y-value is less that 0 will be considered closest
  2062.  * to the first character in the text layout; any point whose y-value
  2063.  * is greater than the height of the text layout will be considered
  2064.  * closest to the last character in the text layout.
  2065.  *
  2066.  * Any point whose x-value is less than 0 will be considered closest
  2067.  * to the first character on that line; any point whose x-value is
  2068.  * greater than the width of the text layout will be considered
  2069.  * closest to the last character on that line.
  2070.  *
  2071.  * Results:
  2072.  * The return value is the index of the character that was
  2073.  * closest to the point.  Given a text layout with no characters,
  2074.  * the value 0 will always be returned, referring to a hypothetical
  2075.  * zero-width placeholder character.
  2076.  *
  2077.  * Side effects:
  2078.  * None.
  2079.  *
  2080.  *---------------------------------------------------------------------------
  2081.  */
  2082. int
  2083. Tk_PointToChar(layout, x, y)
  2084.     Tk_TextLayout layout; /* Layout information, from a previous call
  2085.  * to Tk_ComputeTextLayout(). */
  2086.     int x, y; /* Coordinates of point to check, with
  2087.  * respect to the upper-left corner of the
  2088.  * text layout. */
  2089. {
  2090.     TextLayout *layoutPtr;
  2091.     LayoutChunk *chunkPtr, *lastPtr;
  2092.     TkFont *fontPtr;
  2093.     int i, n, dummy, baseline, pos, numChars;
  2094.     if (y < 0) {
  2095. /*
  2096.  * Point lies above any line in this layout.  Return the index of
  2097.  * the first char.
  2098.  */
  2099. return 0;
  2100.     }
  2101.     /*
  2102.      * Find which line contains the point.
  2103.      */
  2104.     layoutPtr = (TextLayout *) layout;
  2105.     fontPtr = (TkFont *) layoutPtr->tkfont;
  2106.     lastPtr = chunkPtr = layoutPtr->chunks;
  2107.     numChars = 0;
  2108.     for (i = 0; i < layoutPtr->numChunks; i++) {
  2109. baseline = chunkPtr->y;
  2110. if (y < baseline + fontPtr->fm.descent) {
  2111.     if (x < chunkPtr->x) {
  2112. /*
  2113.  * Point is to the left of all chunks on this line.  Return
  2114.  * the index of the first character on this line.
  2115.  */
  2116. return numChars;
  2117.     }
  2118.     if (x >= layoutPtr->width) {
  2119. /*
  2120.  * If point lies off right side of the text layout, return
  2121.  * the last char in the last chunk on this line.  Without
  2122.  * this, it might return the index of the first char that
  2123.  * was located outside of the text layout.
  2124.  */
  2125. x = INT_MAX;
  2126.     }
  2127.     /*
  2128.      * Examine all chunks on this line to see which one contains
  2129.      * the specified point.
  2130.      */
  2131.     lastPtr = chunkPtr;
  2132.     while ((i < layoutPtr->numChunks) && (chunkPtr->y == baseline))  {
  2133. if (x < chunkPtr->x + chunkPtr->totalWidth) {
  2134.     /*
  2135.      * Point falls on one of the characters in this chunk.
  2136.      */
  2137.     if (chunkPtr->numDisplayChars < 0) {
  2138. /*
  2139.  * This is a special chunk that encapsulates a single
  2140.  * tab or newline char.
  2141.  */
  2142. return numChars;
  2143.     }
  2144.     n = Tk_MeasureChars((Tk_Font) fontPtr, chunkPtr->start,
  2145.     chunkPtr->numBytes, x - chunkPtr->x,
  2146.     0, &dummy);
  2147.     return numChars + Tcl_NumUtfChars(chunkPtr->start, n);
  2148. }
  2149. numChars += chunkPtr->numChars;
  2150. lastPtr = chunkPtr;
  2151. chunkPtr++;
  2152. i++;
  2153.     }
  2154.     /*
  2155.      * Point is to the right of all chars in all the chunks on this
  2156.      * line.  Return the index just past the last char in the last
  2157.      * chunk on this line.
  2158.      */
  2159.     pos = numChars;
  2160.     if (i < layoutPtr->numChunks) {
  2161. pos--;
  2162.     }
  2163.     return pos;
  2164. }
  2165. numChars += chunkPtr->numChars;
  2166. lastPtr = chunkPtr;
  2167. chunkPtr++;
  2168.     }
  2169.     /*
  2170.      * Point lies below any line in this text layout.  Return the index
  2171.      * just past the last char.
  2172.      */
  2173.     return (lastPtr->start + lastPtr->numChars) - layoutPtr->string;
  2174. }
  2175. /*
  2176.  *---------------------------------------------------------------------------
  2177.  *
  2178.  * Tk_CharBbox --
  2179.  *
  2180.  * Use the information in the Tk_TextLayout token to return the
  2181.  * bounding box for the character specified by index.  
  2182.  *
  2183.  * The width of the bounding box is the advance width of the
  2184.  * character, and does not include and left- or right-bearing.
  2185.  * Any character that extends partially outside of the
  2186.  * text layout is considered to be truncated at the edge.  Any
  2187.  * character which is located completely outside of the text
  2188.  * layout is considered to be zero-width and pegged against
  2189.  * the edge.
  2190.  *
  2191.  * The height of the bounding box is the line height for this font,
  2192.  * extending from the top of the ascent to the bottom of the
  2193.  * descent.  Information about the actual height of the individual
  2194.  * letter is not available.
  2195.  *
  2196.  * A text layout that contains no characters is considered to
  2197.  * contain a single zero-width placeholder character.
  2198.  * 
  2199.  * Results:
  2200.  * The return value is 0 if the index did not specify a character
  2201.  * in the text layout, or non-zero otherwise.  In that case,
  2202.  * *bbox is filled with the bounding box of the character.
  2203.  *
  2204.  * Side effects:
  2205.  * None.
  2206.  *
  2207.  *---------------------------------------------------------------------------
  2208.  */
  2209. int
  2210. Tk_CharBbox(layout, index, xPtr, yPtr, widthPtr, heightPtr)
  2211.     Tk_TextLayout layout;   /* Layout information, from a previous call to
  2212.      * Tk_ComputeTextLayout(). */
  2213.     int index;     /* The index of the character whose bbox is
  2214.      * desired. */
  2215.     int *xPtr, *yPtr;     /* Filled with the upper-left hand corner, in
  2216.      * pixels, of the bounding box for the character
  2217.      * specified by index, if non-NULL. */
  2218.     int *widthPtr, *heightPtr;
  2219.     /* Filled with the width and height of the
  2220.      * bounding box for the character specified by
  2221.      * index, if non-NULL. */
  2222. {
  2223.     TextLayout *layoutPtr;
  2224.     LayoutChunk *chunkPtr;
  2225.     int i, x, w;
  2226.     Tk_Font tkfont;
  2227.     TkFont *fontPtr;
  2228.     CONST char *end;
  2229.     if (index < 0) {
  2230. return 0;
  2231.     }
  2232.     layoutPtr = (TextLayout *) layout;
  2233.     chunkPtr = layoutPtr->chunks;
  2234.     tkfont = layoutPtr->tkfont;
  2235.     fontPtr = (TkFont *) tkfont;
  2236.     for (i = 0; i < layoutPtr->numChunks; i++) {
  2237. if (chunkPtr->numDisplayChars < 0) {
  2238.     if (index == 0) {
  2239. x = chunkPtr->x;
  2240. w = chunkPtr->totalWidth;
  2241. goto check;
  2242.     }
  2243. } else if (index < chunkPtr->numChars) {
  2244.     end = Tcl_UtfAtIndex(chunkPtr->start, index);
  2245.     if (xPtr != NULL) {
  2246. Tk_MeasureChars(tkfont, chunkPtr->start,
  2247. end -  chunkPtr->start, -1, 0, &x);
  2248. x += chunkPtr->x;
  2249.     }
  2250.     if (widthPtr != NULL) {
  2251. Tk_MeasureChars(tkfont, end, Tcl_UtfNext(end) - end,
  2252. -1, 0, &w);
  2253.     }
  2254.     goto check;
  2255. }
  2256. index -= chunkPtr->numChars;
  2257. chunkPtr++;
  2258.     }
  2259.     if (index == 0) {
  2260. /*
  2261.  * Special case to get location just past last char in layout.
  2262.  */
  2263. chunkPtr--;
  2264. x = chunkPtr->x + chunkPtr->totalWidth;
  2265. w = 0;
  2266.     } else {
  2267. return 0;
  2268.     }
  2269.     /*
  2270.      * Ensure that the bbox lies within the text layout.  This forces all
  2271.      * chars that extend off the right edge of the text layout to have
  2272.      * truncated widths, and all chars that are completely off the right
  2273.      * edge of the text layout to peg to the edge and have 0 width.
  2274.      */
  2275.     check:
  2276.     if (yPtr != NULL) {
  2277. *yPtr = chunkPtr->y - fontPtr->fm.ascent;
  2278.     }
  2279.     if (heightPtr != NULL) {
  2280. *heightPtr = fontPtr->fm.ascent + fontPtr->fm.descent;
  2281.     }
  2282.     if (x > layoutPtr->width) {
  2283. x = layoutPtr->width;
  2284.     }
  2285.     if (xPtr != NULL) {
  2286. *xPtr = x;
  2287.     }
  2288.     if (widthPtr != NULL) {
  2289. if (x + w > layoutPtr->width) {
  2290.     w = layoutPtr->width - x;
  2291. }
  2292. *widthPtr = w;
  2293.     }
  2294.     return 1;
  2295. }
  2296. /*
  2297.  *---------------------------------------------------------------------------
  2298.  *
  2299.  * Tk_DistanceToTextLayout --
  2300.  *
  2301.  * Computes the distance in pixels from the given point to the
  2302.  * given text layout.  Non-displaying space characters that occur
  2303.  * at the end of individual lines in the text layout are ignored
  2304.  * for hit detection purposes.
  2305.  *
  2306.  * Results:
  2307.  * The return value is 0 if the point (x, y) is inside the text
  2308.  * layout.  If the point isn't inside the text layout then the
  2309.  * return value is the distance in pixels from the point to the
  2310.  * text item.
  2311.  *
  2312.  * Side effects:
  2313.  * None.
  2314.  *
  2315.  *---------------------------------------------------------------------------
  2316.  */
  2317. int
  2318. Tk_DistanceToTextLayout(layout, x, y)
  2319.     Tk_TextLayout layout; /* Layout information, from a previous call
  2320.  * to Tk_ComputeTextLayout(). */
  2321.     int x, y; /* Coordinates of point to check, with
  2322.  * respect to the upper-left corner of the
  2323.  * text layout (in pixels). */
  2324. {
  2325.     int i, x1, x2, y1, y2, xDiff, yDiff, dist, minDist, ascent, descent;
  2326.     LayoutChunk *chunkPtr;
  2327.     TextLayout *layoutPtr;
  2328.     TkFont *fontPtr;
  2329.     layoutPtr = (TextLayout *) layout;
  2330.     fontPtr = (TkFont *) layoutPtr->tkfont;
  2331.     ascent = fontPtr->fm.ascent;
  2332.     descent = fontPtr->fm.descent;
  2333.     
  2334.     minDist = 0;
  2335.     chunkPtr = layoutPtr->chunks;
  2336.     for (i = 0; i < layoutPtr->numChunks; i++) {
  2337. if (chunkPtr->start[0] == 'n') {
  2338.     /*
  2339.      * Newline characters are not counted when computing distance
  2340.      * (but tab characters would still be considered).
  2341.      */
  2342.     chunkPtr++;
  2343.     continue;
  2344. }
  2345. x1 = chunkPtr->x;
  2346. y1 = chunkPtr->y - ascent;
  2347. x2 = chunkPtr->x + chunkPtr->displayWidth;
  2348. y2 = chunkPtr->y + descent;
  2349. if (x < x1) {
  2350.     xDiff = x1 - x;
  2351. } else if (x >= x2) {
  2352.     xDiff = x - x2 + 1;
  2353. } else {
  2354.     xDiff = 0;
  2355. }
  2356. if (y < y1) {
  2357.     yDiff = y1 - y;
  2358. } else if (y >= y2) {
  2359.     yDiff = y - y2 + 1;
  2360. } else {
  2361.     yDiff = 0;
  2362. }
  2363. if ((xDiff == 0) && (yDiff == 0)) {
  2364.     return 0;
  2365. }
  2366. dist = (int) hypot((double) xDiff, (double) yDiff);
  2367. if ((dist < minDist) || (minDist == 0)) {
  2368.     minDist = dist;
  2369. }
  2370. chunkPtr++;
  2371.     }
  2372.     return minDist;
  2373. }
  2374. /*
  2375.  *---------------------------------------------------------------------------
  2376.  *
  2377.  * Tk_IntersectTextLayout --
  2378.  *
  2379.  * Determines whether a text layout lies entirely inside,
  2380.  * entirely outside, or overlaps a given rectangle.  Non-displaying
  2381.  * space characters that occur at the end of individual lines in
  2382.  * the text layout are ignored for intersection calculations.
  2383.  *
  2384.  * Results:
  2385.  * The return value is -1 if the text layout is entirely outside of
  2386.  * the rectangle, 0 if it overlaps, and 1 if it is entirely inside
  2387.  * of the rectangle.
  2388.  *
  2389.  * Side effects:
  2390.  * None.
  2391.  *
  2392.  *---------------------------------------------------------------------------
  2393.  */
  2394. int
  2395. Tk_IntersectTextLayout(layout, x, y, width, height)
  2396.     Tk_TextLayout layout; /* Layout information, from a previous call
  2397.  * to Tk_ComputeTextLayout(). */
  2398.     int x, y; /* Upper-left hand corner, in pixels, of
  2399.  * rectangular area to compare with text
  2400.  * layout.  Coordinates are with respect to
  2401.  * the upper-left hand corner of the text
  2402.  * layout itself. */
  2403.     int width, height; /* The width and height of the above
  2404.  * rectangular area, in pixels. */
  2405. {
  2406.     int result, i, x1, y1, x2, y2;
  2407.     TextLayout *layoutPtr;
  2408.     LayoutChunk *chunkPtr;
  2409.     TkFont *fontPtr;
  2410.     int left, top, right, bottom;
  2411.     /*
  2412.      * Scan the chunks one at a time, seeing whether each is entirely in,
  2413.      * entirely out, or overlapping the rectangle.  If an overlap is
  2414.      * detected, return immediately; otherwise wait until all chunks have
  2415.      * been processed and see if they were all inside or all outside.
  2416.      */
  2417.     
  2418.     layoutPtr = (TextLayout *) layout;
  2419.     chunkPtr = layoutPtr->chunks;
  2420.     fontPtr = (TkFont *) layoutPtr->tkfont;
  2421.     left    = x;
  2422.     top     = y;
  2423.     right   = x + width;
  2424.     bottom  = y + height;
  2425.     result = 0;
  2426.     for (i = 0; i < layoutPtr->numChunks; i++) {
  2427. if (chunkPtr->start[0] == 'n') {
  2428.     /*
  2429.      * Newline characters are not counted when computing area
  2430.      * intersection (but tab characters would still be considered).
  2431.      */
  2432.     chunkPtr++;
  2433.     continue;
  2434. }
  2435. x1 = chunkPtr->x;
  2436. y1 = chunkPtr->y - fontPtr->fm.ascent;
  2437. x2 = chunkPtr->x + chunkPtr->displayWidth;
  2438. y2 = chunkPtr->y + fontPtr->fm.descent;
  2439. if ((right < x1) || (left >= x2)
  2440. || (bottom < y1) || (top >= y2)) {
  2441.     if (result == 1) {
  2442. return 0;
  2443.     }
  2444.     result = -1;
  2445. } else if ((x1 < left) || (x2 >= right)
  2446. || (y1 < top) || (y2 >= bottom)) {
  2447.     return 0;
  2448. } else if (result == -1) {
  2449.     return 0;
  2450. } else {
  2451.     result = 1;
  2452. }
  2453. chunkPtr++;
  2454.     }
  2455.     return result;
  2456. }
  2457. /*
  2458.  *---------------------------------------------------------------------------
  2459.  *
  2460.  * Tk_TextLayoutToPostscript --
  2461.  *
  2462.  * Outputs the contents of a text layout in Postscript format.
  2463.  * The set of lines in the text layout will be rendered by the user
  2464.  * supplied Postscript function.  The function should be of the form:
  2465.  *
  2466.  *     justify x y string  function  --
  2467.  *
  2468.  * Justify is -1, 0, or 1, depending on whether the following string
  2469.  * should be left, center, or right justified, x and y is the
  2470.  * location for the origin of the string, string is the sequence
  2471.  * of characters to be printed, and function is the name of the
  2472.  * caller-provided function; the function should leave nothing
  2473.  * on the stack.
  2474.  *
  2475.  * The meaning of the origin of the string (x and y) depends on
  2476.  * the justification.  For left justification, x is where the
  2477.  * left edge of the string should appear.  For center justification,
  2478.  * x is where the center of the string should appear.  And for right
  2479.  * justification, x is where the right edge of the string should
  2480.  * appear.  This behavior is necessary because, for example, right
  2481.  * justified text on the screen is justified with screen metrics.
  2482.  * The same string needs to be justified with printer metrics on
  2483.  * the printer to appear in the correct place with respect to other
  2484.  * similarly justified strings.  In all circumstances, y is the
  2485.  * location of the baseline for the string.
  2486.  *
  2487.  * Results:
  2488.  * The interp's result is modified to hold the Postscript code that
  2489.  * will render the text layout.
  2490.  *
  2491.  * Side effects:
  2492.  * None.
  2493.  *
  2494.  *---------------------------------------------------------------------------
  2495.  */
  2496. void
  2497. Tk_TextLayoutToPostscript(interp, layout)
  2498.     Tcl_Interp *interp; /* Filled with Postscript code. */
  2499.     Tk_TextLayout layout; /* The layout to be rendered. */
  2500. {
  2501. #define MAXUSE 128
  2502.     char buf[MAXUSE+30];
  2503.     LayoutChunk *chunkPtr;
  2504.     int i, j, used, c, baseline;
  2505.     Tcl_UniChar ch;
  2506.     CONST char *p, *last_p,*glyphname;
  2507.     TextLayout *layoutPtr;
  2508.     char uindex[5]="";
  2509.     char one_char[5];
  2510.     int charsize;
  2511.     int bytecount=0;
  2512.     layoutPtr = (TextLayout *) layout;
  2513.     chunkPtr = layoutPtr->chunks;
  2514.     baseline = chunkPtr->y;
  2515.     used = 0;
  2516.     buf[used++] = '[';
  2517.     buf[used++] = '(';
  2518.     for (i = 0; i < layoutPtr->numChunks; i++) {
  2519. if (baseline != chunkPtr->y) {
  2520.     buf[used++] = ')';
  2521.     buf[used++] = ']';
  2522.     buf[used++] = 'n';
  2523.     buf[used++] = '[';
  2524.     buf[used++] = '(';
  2525.     baseline = chunkPtr->y;
  2526. }
  2527. if (chunkPtr->numDisplayChars <= 0) {
  2528.     if (chunkPtr->start[0] == 't') {
  2529. buf[used++] = '\';
  2530. buf[used++] = 't';
  2531.     }
  2532. } else {
  2533.     p = chunkPtr->start;
  2534.     for (j = 0; j < chunkPtr->numDisplayChars; j++) {
  2535. /*
  2536.  * INTL: For now we just treat the characters as binary
  2537.  * data and display the lower byte.  Eventually this should
  2538.  * be revised to handle international postscript fonts.
  2539.  */
  2540. last_p=p;
  2541. p +=(charsize= Tcl_UtfToUniChar(p,&ch));
  2542. Tcl_UtfToExternal(interp,NULL,last_p,charsize,0,NULL,one_char,4,
  2543. NULL,&bytecount,NULL); 
  2544.                 if (bytecount == 1) {
  2545.     c = UCHAR(one_char[0]);
  2546.     /* c = UCHAR( ch & 0xFF) */;
  2547.     if ((c == '(') || (c == ')') || (c == '\') || (c < 0x20)
  2548.     || (c >= UCHAR(0x7f))) {
  2549. /*
  2550.  * Tricky point:  the "03" is necessary in the sprintf
  2551.  * below, so that a full three digits of octal are
  2552.  * always generated.  Without the "03", a number
  2553.  * following this sequence could be interpreted by
  2554.  * Postscript as part of this sequence.
  2555.  */
  2556. sprintf(buf + used, "\%03o", c);
  2557. used += 4;
  2558.     } else {
  2559. buf[used++] = c;
  2560.     }
  2561. } else {
  2562.     /* This character doesn't belong to system character set.
  2563.      * So, we must use full glyph name */
  2564.     sprintf(uindex,"%04X",ch); /* endianness? */
  2565.     if ((glyphname = Tcl_GetVar2( interp , "::tk::psglyphs",uindex,0))) {
  2566. if (used > 0 && buf [used-1] == '(') 
  2567.     --used;
  2568. else
  2569.     buf[used++] = ')';
  2570. buf[used++] = '/';
  2571. while( (*glyphname) && (used < (MAXUSE+27))) 
  2572.     buf[used++] = *glyphname++ ;
  2573. buf[used++] = '(';
  2574.     }
  2575.     
  2576. }
  2577. if (used >= MAXUSE) {
  2578.     buf[used] = '';
  2579.     Tcl_AppendResult(interp, buf, (char *) NULL);
  2580.     used = 0;
  2581. }
  2582.     }
  2583. }
  2584. if (used >= MAXUSE) {
  2585.     /*
  2586.      * If there are a whole bunch of returns or tabs in a row,
  2587.      * then buf[] could get filled up.
  2588.      */
  2589.      
  2590.     buf[used] = '';
  2591.     Tcl_AppendResult(interp, buf, (char *) NULL);
  2592.     used = 0;
  2593. }
  2594. chunkPtr++;
  2595.     }
  2596.     buf[used++] = ')';
  2597.     buf[used++] = ']';
  2598.     buf[used++] = 'n';
  2599.     buf[used] = '';
  2600.     Tcl_AppendResult(interp, buf, (char *) NULL);
  2601. }
  2602. /*
  2603.  *---------------------------------------------------------------------------
  2604.  *
  2605.  * ConfigAttributesObj --
  2606.  *
  2607.  * Process command line options to fill in fields of a properly
  2608.  * initialized font attributes structure.
  2609.  *
  2610.  * Results:
  2611.  * A standard Tcl return value.  If TCL_ERROR is returned, an
  2612.  * error message will be left in interp's result object (if non-NULL).
  2613.  *
  2614.  * Side effects:
  2615.  * The fields of the font attributes structure get filled in with
  2616.  * information from argc/argv.  If an error occurs while parsing,
  2617.  * the font attributes structure will contain all modifications
  2618.  * specified in the command line options up to the point of the
  2619.  * error.
  2620.  *
  2621.  *---------------------------------------------------------------------------
  2622.  */
  2623. static int
  2624. ConfigAttributesObj(interp, tkwin, objc, objv, faPtr)
  2625.     Tcl_Interp *interp; /* Interp for error return, or NULL. */
  2626.     Tk_Window tkwin; /* For display on which font will be used. */
  2627.     int objc; /* Number of elements in argv. */
  2628.     Tcl_Obj *CONST objv[]; /* Command line options. */
  2629.     TkFontAttributes *faPtr; /* Font attributes structure whose fields
  2630.  * are to be modified.  Structure must already
  2631.  * be properly initialized. */
  2632. {
  2633.     int i, n, index;
  2634.     Tcl_Obj *optionPtr, *valuePtr;
  2635.     char *value;
  2636.     
  2637.     for (i = 0; i < objc; i += 2) {
  2638. optionPtr = objv[i];
  2639. valuePtr = objv[i + 1];
  2640. if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1,
  2641. &index) != TCL_OK) {
  2642.     return TCL_ERROR;
  2643. }
  2644. if ((i+2 >= objc) && (objc & 1)) {
  2645.     /*
  2646.      * This test occurs after Tcl_GetIndexFromObj() so that
  2647.      * "font create xyz -xyz" will return the error message
  2648.      * that "-xyz" is a bad option, rather than that the value
  2649.      * for "-xyz" is missing.
  2650.      */
  2651.     if (interp != NULL) {
  2652. Tcl_AppendResult(interp, "value for "",
  2653. Tcl_GetString(optionPtr), "" option missing",
  2654. (char *) NULL);
  2655.     }
  2656.     return TCL_ERROR;
  2657. }
  2658. switch (index) {
  2659.     case FONT_FAMILY: {
  2660. value = Tcl_GetString(valuePtr);
  2661. faPtr->family = Tk_GetUid(value);
  2662. break;
  2663.     }
  2664.     case FONT_SIZE: {
  2665. if (Tcl_GetIntFromObj(interp, valuePtr, &n) != TCL_OK) {
  2666.     return TCL_ERROR;
  2667. }
  2668. faPtr->size = n;
  2669. break;
  2670.     }
  2671.     case FONT_WEIGHT: {
  2672. n = TkFindStateNumObj(interp, optionPtr, weightMap, valuePtr);
  2673. if (n == TK_FW_UNKNOWN) {
  2674.     return TCL_ERROR;
  2675. }
  2676. faPtr->weight = n;
  2677. break;
  2678.     }
  2679.     case FONT_SLANT: {
  2680. n = TkFindStateNumObj(interp, optionPtr, slantMap, valuePtr);
  2681. if (n == TK_FS_UNKNOWN) {
  2682.     return TCL_ERROR;
  2683. }
  2684. faPtr->slant = n;
  2685. break;
  2686.     }
  2687.     case FONT_UNDERLINE: {
  2688. if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) {
  2689.     return TCL_ERROR;
  2690. }
  2691. faPtr->underline = n;
  2692. break;
  2693.     }
  2694.     case FONT_OVERSTRIKE: {
  2695. if (Tcl_GetBooleanFromObj(interp, valuePtr, &n) != TCL_OK) {
  2696.     return TCL_ERROR;
  2697. }
  2698. faPtr->overstrike = n;
  2699. break;
  2700.     }
  2701. }
  2702.     }
  2703.     return TCL_OK;
  2704. }
  2705. /*
  2706.  *---------------------------------------------------------------------------
  2707.  *
  2708.  * GetAttributeInfoObj --
  2709.  *
  2710.  * Return information about the font attributes as a Tcl list.
  2711.  *
  2712.  * Results:
  2713.  * The return value is TCL_OK if the objPtr was non-NULL and
  2714.  * specified a valid font attribute, TCL_ERROR otherwise.  If TCL_OK
  2715.  * is returned, the interp's result object is modified to hold a
  2716.  * description of either the current value of a single option, or a
  2717.  * list of all options and their current values for the given font
  2718.  * attributes.  If TCL_ERROR is returned, the interp's result is
  2719.  * set to an error message describing that the objPtr did not refer
  2720.  * to a valid option.
  2721.  *
  2722.  * Side effects:
  2723.  * None.
  2724.  *
  2725.  *---------------------------------------------------------------------------
  2726.  */
  2727. static int
  2728. GetAttributeInfoObj(interp, faPtr, objPtr)
  2729.     Tcl_Interp *interp;    /* Interp to hold result. */
  2730.     CONST TkFontAttributes *faPtr; /* The font attributes to inspect. */
  2731.     Tcl_Obj *objPtr;    /* If non-NULL, indicates the single
  2732.  * option whose value is to be
  2733.  * returned. Otherwise information is
  2734.  * returned for all options. */
  2735. {
  2736.     int i, index, start, end;
  2737.     CONST char *str;
  2738.     Tcl_Obj *optionPtr, *valuePtr, *resultPtr;
  2739.     resultPtr = Tcl_GetObjResult(interp);
  2740.     start = 0;
  2741.     end = FONT_NUMFIELDS;
  2742.     if (objPtr != NULL) {
  2743. if (Tcl_GetIndexFromObj(interp, objPtr, fontOpt, "option", TCL_EXACT,
  2744. &index) != TCL_OK) {
  2745.     return TCL_ERROR;
  2746. }
  2747. start = index;
  2748. end = index + 1;
  2749.     }
  2750.     valuePtr = NULL;
  2751.     for (i = start; i < end; i++) {
  2752. switch (i) {
  2753.     case FONT_FAMILY:
  2754. str = faPtr->family;
  2755. valuePtr = Tcl_NewStringObj(str, ((str == NULL) ? 0 : -1));
  2756. break;
  2757.     case FONT_SIZE:
  2758. valuePtr = Tcl_NewIntObj(faPtr->size);
  2759. break;
  2760.     case FONT_WEIGHT:
  2761. str = TkFindStateString(weightMap, faPtr->weight);
  2762. valuePtr = Tcl_NewStringObj(str, -1);
  2763. break;
  2764.     case FONT_SLANT:
  2765. str = TkFindStateString(slantMap, faPtr->slant);
  2766. valuePtr = Tcl_NewStringObj(str, -1);
  2767. break;
  2768.     case FONT_UNDERLINE:
  2769. valuePtr = Tcl_NewBooleanObj(faPtr->underline);
  2770. break;
  2771.     case FONT_OVERSTRIKE:
  2772. valuePtr = Tcl_NewBooleanObj(faPtr->overstrike);
  2773. break;
  2774. }
  2775. if (objPtr != NULL) {
  2776.     Tcl_SetObjResult(interp, valuePtr);
  2777.     return TCL_OK;
  2778. }
  2779. optionPtr = Tcl_NewStringObj(fontOpt[i], -1);
  2780. Tcl_ListObjAppendElement(NULL, resultPtr, optionPtr);
  2781. Tcl_ListObjAppendElement(NULL, resultPtr, valuePtr);
  2782.     }
  2783.     return TCL_OK;
  2784. }
  2785. /*
  2786.  *---------------------------------------------------------------------------
  2787.  *
  2788.  * ParseFontNameObj --
  2789.  *
  2790.  * Converts a object into a set of font attributes that can be used
  2791.  * to construct a font.
  2792.  *
  2793.  * The string rep of the object can be one of the following forms:
  2794.  * XLFD (see X documentation)
  2795.  * "family [size] [style1 [style2 ...]"
  2796.  * "-option value [-option value ...]"
  2797.  *
  2798.  * Results:
  2799.  * The return value is TCL_ERROR if the object was syntactically
  2800.  * invalid.  In that case an error message is left in interp's
  2801.  * result object.  Otherwise, fills the font attribute buffer with
  2802.  * the values parsed from the string and returns TCL_OK;
  2803.  *
  2804.  * Side effects:
  2805.  * None.
  2806.  *
  2807.  *---------------------------------------------------------------------------
  2808.  */
  2809. static int
  2810. ParseFontNameObj(interp, tkwin, objPtr, faPtr)
  2811.     Tcl_Interp *interp; /* Interp for error return, or NULL if no
  2812.  * error messages are to be generated. */
  2813.     Tk_Window tkwin; /* For display on which font is used. */
  2814.     Tcl_Obj *objPtr; /* Parseable font description object. */
  2815.     TkFontAttributes *faPtr; /* Filled with attributes parsed from font
  2816.  * name.  Any attributes that were not
  2817.  * specified in font name are filled with
  2818.  * default values. */
  2819. {
  2820.     char *dash;
  2821.     int objc, result, i, n;
  2822.     Tcl_Obj **objv;
  2823.     char *string;
  2824.     
  2825.     TkInitFontAttributes(faPtr);
  2826.     string = Tcl_GetString(objPtr);
  2827.     if (*string == '-') {
  2828. /*
  2829.  * This may be an XLFD or an "-option value" string.
  2830.  *
  2831.  * If the string begins with "-*" or a "-foundry-family-*" pattern,
  2832.  * then consider it an XLFD.  
  2833.  */
  2834. if (string[1] == '*') {
  2835.     goto xlfd;
  2836. }
  2837. dash = strchr(string + 1, '-');
  2838. if ((dash != NULL)
  2839. && (!isspace(UCHAR(dash[-1])))) { /* INTL: ISO space */
  2840.     goto xlfd;
  2841. }
  2842. if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
  2843.     return TCL_ERROR;
  2844. }
  2845. return ConfigAttributesObj(interp, tkwin, objc, objv, faPtr);
  2846.     }
  2847.     
  2848.     if (*string == '*') {
  2849. /*
  2850.  * This is appears to be an XLFD.  Under Unix, all valid XLFDs were
  2851.  * already handled by TkpGetNativeFont.  If we are here, either we
  2852.  * have something that initially looks like an XLFD but isn't or we
  2853.  * have encountered an XLFD on Windows or Mac.
  2854.  */
  2855.     xlfd:
  2856. result = TkFontParseXLFD(string, faPtr, NULL);
  2857. if (result == TCL_OK) {
  2858.     return TCL_OK;
  2859. }
  2860.     }
  2861.     /*
  2862.      * Wasn't an XLFD or "-option value" string.  Try it as a
  2863.      * "font size style" list.
  2864.      */
  2865.     if ((Tcl_ListObjGetElements(NULL, objPtr, &objc, &objv) != TCL_OK)
  2866.     || (objc < 1)) {
  2867. if (interp != NULL) {
  2868.     Tcl_AppendResult(interp, "font "", string, "" doesn't exist",
  2869.     (char *) NULL);
  2870. }
  2871. return TCL_ERROR;
  2872.     }
  2873.     faPtr->family = Tk_GetUid(Tcl_GetString(objv[0]));
  2874.     if (objc > 1) {
  2875. if (Tcl_GetIntFromObj(interp, objv[1], &n) != TCL_OK) {
  2876.     return TCL_ERROR;
  2877. }
  2878. faPtr->size = n;
  2879.     }
  2880.     i = 2;
  2881.     if (objc == 3) {
  2882. if (Tcl_ListObjGetElements(interp, objv[2], &objc, &objv) != TCL_OK) {
  2883.     return TCL_ERROR;
  2884. }
  2885. i = 0;
  2886.     }
  2887.     for ( ; i < objc; i++) {
  2888. n = TkFindStateNumObj(NULL, NULL, weightMap, objv[i]);
  2889. if (n != TK_FW_UNKNOWN) {
  2890.     faPtr->weight = n;
  2891.     continue;
  2892. }
  2893. n = TkFindStateNumObj(NULL, NULL, slantMap, objv[i]);
  2894. if (n != TK_FS_UNKNOWN) {
  2895.     faPtr->slant = n;
  2896.     continue;
  2897. }
  2898. n = TkFindStateNumObj(NULL, NULL, underlineMap, objv[i]);
  2899. if (n != 0) {
  2900.     faPtr->underline = n;
  2901.     continue;
  2902. }
  2903. n = TkFindStateNumObj(NULL, NULL, overstrikeMap, objv[i]);
  2904. if (n != 0) {
  2905.     faPtr->overstrike = n;
  2906.     continue;
  2907. }
  2908. /*
  2909.  * Unknown style.
  2910.  */
  2911. if (interp != NULL) {
  2912.     Tcl_AppendResult(interp, "unknown font style "",
  2913.     Tcl_GetString(objv[i]), """, (char *) NULL);
  2914. }
  2915. return TCL_ERROR;
  2916.     }
  2917.     return TCL_OK;
  2918. }
  2919. /*
  2920.  *---------------------------------------------------------------------------
  2921.  *
  2922.  * NewChunk --
  2923.  *
  2924.  * Helper function for Tk_ComputeTextLayout().  Encapsulates a
  2925.  * measured set of characters in a chunk that can be quickly
  2926.  * drawn.
  2927.  *
  2928.  * Results:
  2929.  * A pointer to the new chunk in the text layout.
  2930.  *
  2931.  * Side effects:
  2932.  * The text layout is reallocated to hold more chunks as necessary.
  2933.  *
  2934.  * Currently, Tk_ComputeTextLayout() stores contiguous ranges of
  2935.  * "normal" characters in a chunk, along with individual tab
  2936.  * and newline chars in their own chunks.  All characters in the
  2937.  * text layout are accounted for.
  2938.  *
  2939.  *---------------------------------------------------------------------------
  2940.  */
  2941. static LayoutChunk *
  2942. NewChunk(layoutPtrPtr, maxPtr, start, numBytes, curX, newX, y)
  2943.     TextLayout **layoutPtrPtr;
  2944.     int *maxPtr;
  2945.     CONST char *start;
  2946.     int numBytes;
  2947.     int curX;
  2948.     int newX;
  2949.     int y;
  2950. {
  2951.     TextLayout *layoutPtr;
  2952.     LayoutChunk *chunkPtr;
  2953.     int maxChunks, numChars;
  2954.     size_t s;
  2955.     
  2956.     layoutPtr = *layoutPtrPtr;
  2957.     maxChunks = *maxPtr;
  2958.     if (layoutPtr->numChunks == maxChunks) {
  2959. maxChunks *= 2;
  2960. s = sizeof(TextLayout) + ((maxChunks - 1) * sizeof(LayoutChunk));
  2961. layoutPtr = (TextLayout *) ckrealloc((char *) layoutPtr, s);
  2962. *layoutPtrPtr = layoutPtr;
  2963. *maxPtr = maxChunks;
  2964.     }
  2965.     numChars = Tcl_NumUtfChars(start, numBytes);
  2966.     chunkPtr = &layoutPtr->chunks[layoutPtr->numChunks];
  2967.     chunkPtr->start = start;
  2968.     chunkPtr->numBytes = numBytes;
  2969.     chunkPtr->numChars = numChars;
  2970.     chunkPtr->numDisplayChars = numChars;
  2971.     chunkPtr->x = curX;
  2972.     chunkPtr->y = y;
  2973.     chunkPtr->totalWidth = newX - curX;
  2974.     chunkPtr->displayWidth = newX - curX;
  2975.     layoutPtr->numChunks++;
  2976.     return chunkPtr;
  2977. }
  2978. /*
  2979.  *---------------------------------------------------------------------------
  2980.  *
  2981.  * TkFontParseXLFD --
  2982.  *
  2983.  * Break up a fully specified XLFD into a set of font attributes.
  2984.  *
  2985.  * Results:
  2986.  * Return value is TCL_ERROR if string was not a fully specified XLFD.
  2987.  * Otherwise, fills font attribute buffer with the values parsed
  2988.  * from the XLFD and returns TCL_OK.  
  2989.  *
  2990.  * Side effects:
  2991.  * None.
  2992.  *
  2993.  *---------------------------------------------------------------------------
  2994.  */
  2995. int
  2996. TkFontParseXLFD(string, faPtr, xaPtr)
  2997.     CONST char *string; /* Parseable font description string. */
  2998.     TkFontAttributes *faPtr; /* Filled with attributes parsed from font
  2999.  * name.  Any attributes that were not
  3000.  * specified in font name are filled with
  3001.  * default values. */
  3002.     TkXLFDAttributes *xaPtr; /* Filled with X-specific attributes parsed
  3003.  * from font name.  Any attributes that were
  3004.  * not specified in font name are filled with
  3005.  * default values.  May be NULL if such
  3006.  * information is not desired. */
  3007. {
  3008.     char *src;
  3009.     CONST char *str;
  3010.     int i, j;
  3011.     char *field[XLFD_NUMFIELDS + 2];
  3012.     Tcl_DString ds;
  3013.     TkXLFDAttributes xa;
  3014.     
  3015.     if (xaPtr == NULL) {
  3016. xaPtr = &xa;
  3017.     }
  3018.     TkInitFontAttributes(faPtr);
  3019.     TkInitXLFDAttributes(xaPtr);
  3020.     memset(field, '', sizeof(field));
  3021.     str = string;
  3022.     if (*str == '-') {
  3023. str++;
  3024.     }
  3025.     Tcl_DStringInit(&ds);
  3026.     Tcl_DStringAppend(&ds, (char *) str, -1);
  3027.     src = Tcl_DStringValue(&ds);
  3028.     field[0] = src;
  3029.     for (i = 0; *src != ''; src++) {
  3030. if (!(*src & 0x80)
  3031. && Tcl_UniCharIsUpper(UCHAR(*src))) {
  3032.     *src = (char) Tcl_UniCharToLower(UCHAR(*src));
  3033. }
  3034. if (*src == '-') {
  3035.     i++;
  3036.     if (i == XLFD_NUMFIELDS) {
  3037. continue;
  3038.     }
  3039.     *src = '';
  3040.     field[i] = src + 1;
  3041.     if (i > XLFD_NUMFIELDS) {
  3042. break;
  3043.     }
  3044. }
  3045.     }
  3046.     /*
  3047.      * An XLFD of the form -adobe-times-medium-r-*-12-*-* is pretty common,
  3048.      * but it is (strictly) malformed, because the first * is eliding both
  3049.      * the Setwidth and the Addstyle fields.  If the Addstyle field is a
  3050.      * number, then assume the above incorrect form was used and shift all
  3051.      * the rest of the fields right by one, so the number gets interpreted
  3052.      * as a pixelsize.  This fix is so that we don't get a million reports
  3053.      * that "it works under X (as a native font name), but gives a syntax
  3054.      * error under Windows (as a parsed set of attributes)".
  3055.      */
  3056.     if ((i > XLFD_ADD_STYLE) && (FieldSpecified(field[XLFD_ADD_STYLE]))) {
  3057. if (atoi(field[XLFD_ADD_STYLE]) != 0) {
  3058.     for (j = XLFD_NUMFIELDS - 1; j >= XLFD_ADD_STYLE; j--) {
  3059. field[j + 1] = field[j];
  3060.     }
  3061.     field[XLFD_ADD_STYLE] = NULL;
  3062.     i++;
  3063. }
  3064.     }
  3065.     /*
  3066.      * Bail if we don't have enough of the fields (up to pointsize).
  3067.      */
  3068.     if (i < XLFD_FAMILY) {
  3069. Tcl_DStringFree(&ds);
  3070. return TCL_ERROR;
  3071.     }
  3072.     if (FieldSpecified(field[XLFD_FOUNDRY])) {
  3073. xaPtr->foundry = Tk_GetUid(field[XLFD_FOUNDRY]);
  3074.     }
  3075.     if (FieldSpecified(field[XLFD_FAMILY])) {
  3076. faPtr->family = Tk_GetUid(field[XLFD_FAMILY]);
  3077.     }
  3078.     if (FieldSpecified(field[XLFD_WEIGHT])) {
  3079. faPtr->weight = TkFindStateNum(NULL, NULL, xlfdWeightMap,
  3080. field[XLFD_WEIGHT]);
  3081.     }
  3082.     if (FieldSpecified(field[XLFD_SLANT])) {
  3083. xaPtr->slant = TkFindStateNum(NULL, NULL, xlfdSlantMap,
  3084. field[XLFD_SLANT]);
  3085. if (xaPtr->slant == TK_FS_ROMAN) {
  3086.     faPtr->slant = TK_FS_ROMAN;
  3087. } else {
  3088.     faPtr->slant = TK_FS_ITALIC;
  3089. }
  3090.     }
  3091.     if (FieldSpecified(field[XLFD_SETWIDTH])) {
  3092. xaPtr->setwidth = TkFindStateNum(NULL, NULL, xlfdSetwidthMap,
  3093. field[XLFD_SETWIDTH]);
  3094.     }
  3095.     /* XLFD_ADD_STYLE ignored. */
  3096.     /*
  3097.      * Pointsize in tenths of a point, but treat it as tenths of a pixel
  3098.      * for historical compatibility.
  3099.      */
  3100.     faPtr->size = 12;
  3101.     if (FieldSpecified(field[XLFD_POINT_SIZE])) {
  3102. if (field[XLFD_POINT_SIZE][0] == '[') {
  3103.     /*
  3104.      * Some X fonts have the point size specified as follows:
  3105.      *
  3106.      *     [ N1 N2 N3 N4 ]
  3107.      *
  3108.      * where N1 is the point size (in points, not decipoints!), and
  3109.      * N2, N3, and N4 are some additional numbers that I don't know
  3110.      * the purpose of, so I ignore them.
  3111.      */
  3112.     faPtr->size = atoi(field[XLFD_POINT_SIZE] + 1);
  3113. } else if (Tcl_GetInt(NULL, field[XLFD_POINT_SIZE],
  3114. &faPtr->size) == TCL_OK) {
  3115.     faPtr->size /= 10;
  3116. } else {
  3117.     return TCL_ERROR;
  3118. }
  3119.     }
  3120.     /*
  3121.      * Pixel height of font.  If specified, overrides pointsize.
  3122.      */
  3123.     if (FieldSpecified(field[XLFD_PIXEL_SIZE])) {
  3124. if (field[XLFD_PIXEL_SIZE][0] == '[') {
  3125.     /*
  3126.      * Some X fonts have the pixel size specified as follows:
  3127.      *
  3128.      *     [ N1 N2 N3 N4 ]
  3129.      *
  3130.      * where N1 is the pixel size, and where N2, N3, and N4 
  3131.      * are some additional numbers that I don't know
  3132.      * the purpose of, so I ignore them.
  3133.      */
  3134.     faPtr->size = atoi(field[XLFD_PIXEL_SIZE] + 1);
  3135. } else if (Tcl_GetInt(NULL, field[XLFD_PIXEL_SIZE],
  3136. &faPtr->size) != TCL_OK) {
  3137.     return TCL_ERROR;
  3138. }
  3139.     }
  3140.     faPtr->size = -faPtr->size;
  3141.     /* XLFD_RESOLUTION_X ignored. */
  3142.     /* XLFD_RESOLUTION_Y ignored. */
  3143.     /* XLFD_SPACING ignored. */
  3144.     /* XLFD_AVERAGE_WIDTH ignored. */
  3145.     if (FieldSpecified(field[XLFD_CHARSET])) {
  3146. xaPtr->charset = Tk_GetUid(field[XLFD_CHARSET]);
  3147.     } else {
  3148. xaPtr->charset = Tk_GetUid("iso8859-1");
  3149.     }
  3150.     Tcl_DStringFree(&ds);
  3151.     return TCL_OK;
  3152. }
  3153. /*
  3154.  *---------------------------------------------------------------------------
  3155.  *
  3156.  * FieldSpecified --
  3157.  *
  3158.  * Helper function for TkParseXLFD().  Determines if a field in the
  3159.  * XLFD was set to a non-null, non-don't-care value.
  3160.  *
  3161.  * Results:
  3162.  * The return value is 0 if the field in the XLFD was not set and
  3163.  * should be ignored, non-zero otherwise.
  3164.  *
  3165.  * Side effects:
  3166.  * None.
  3167.  *
  3168.  *---------------------------------------------------------------------------
  3169.  */
  3170. static int
  3171. FieldSpecified(field)
  3172.     CONST char *field; /* The field of the XLFD to check.  Strictly
  3173.  * speaking, only when the string is "*" does it mean
  3174.  * don't-care.  However, an unspecified or question
  3175.  * mark is also interpreted as don't-care. */
  3176. {
  3177.     char ch;
  3178.     if (field == NULL) {
  3179. return 0;
  3180.     }
  3181.     ch = field[0];
  3182.     return (ch != '*' && ch != '?');
  3183. }
  3184. /*
  3185.  *---------------------------------------------------------------------------
  3186.  *
  3187.  * TkFontGetPixels --
  3188.  *
  3189.  * Given a font size specification (as described in the TkFontAttributes
  3190.  * structure) return the number of pixels it represents.
  3191.  *
  3192.  * Results:
  3193.  * As above.
  3194.  *
  3195.  * Side effects:
  3196.  * None.
  3197.  *
  3198.  *---------------------------------------------------------------------------
  3199.  */
  3200.  
  3201. int
  3202. TkFontGetPixels(tkwin, size)
  3203.     Tk_Window tkwin; /* For point->pixel conversion factor. */
  3204.     int size; /* Font size. */
  3205. {
  3206.     double d;
  3207.     if (size < 0) {
  3208. return -size;
  3209.     }
  3210.     d = size * 25.4 / 72.0;
  3211.     d *= WidthOfScreen(Tk_Screen(tkwin));
  3212.     d /= WidthMMOfScreen(Tk_Screen(tkwin));
  3213.     return (int) (d + 0.5);
  3214. }
  3215. /*
  3216.  *---------------------------------------------------------------------------
  3217.  *
  3218.  * TkFontGetPoints --
  3219.  *
  3220.  * Given a font size specification (as described in the TkFontAttributes
  3221.  * structure) return the number of points it represents.
  3222.  *
  3223.  * Results:
  3224.  * As above.
  3225.  *
  3226.  * Side effects:
  3227.  * None.
  3228.  *
  3229.  *---------------------------------------------------------------------------
  3230.  */
  3231.  
  3232. int
  3233. TkFontGetPoints(tkwin, size)
  3234.     Tk_Window tkwin; /* For pixel->point conversion factor. */
  3235.     int size; /* Font size. */
  3236. {
  3237.     double d;
  3238.     if (size >= 0) {
  3239. return size;
  3240.     }
  3241.     d = -size * 72.0 / 25.4;
  3242.     d *= WidthMMOfScreen(Tk_Screen(tkwin));
  3243.     d /= WidthOfScreen(Tk_Screen(tkwin));
  3244.     return (int) (d + 0.5);
  3245. }
  3246. /*
  3247.  *-------------------------------------------------------------------------
  3248.  *
  3249.  * TkFontGetAliasList --
  3250.  *
  3251.  * Given a font name, find the list of all aliases for that font
  3252.  * name.  One of the names in this list will probably be the name
  3253.  * that this platform expects when asking for the font.
  3254.  *
  3255.  * Results:
  3256.  * As above.  The return value is NULL if the font name has no 
  3257.  * aliases.
  3258.  *
  3259.  * Side effects:
  3260.  * None.
  3261.  *
  3262.  *-------------------------------------------------------------------------
  3263.  */
  3264. char **
  3265. TkFontGetAliasList(faceName)
  3266.     CONST char *faceName; /* Font name to test for aliases. */
  3267. {   
  3268.     int i, j;
  3269.     for (i = 0; fontAliases[i] != NULL; i++) {
  3270. for (j = 0; fontAliases[i][j] != NULL; j++) {
  3271.     if (strcasecmp(faceName, fontAliases[i][j]) == 0) {
  3272. return fontAliases[i];
  3273.     }
  3274. }
  3275.     }
  3276.     return NULL;
  3277. }
  3278. /*
  3279.  *-------------------------------------------------------------------------
  3280.  *
  3281.  * TkFontGetFallbacks --
  3282.  *
  3283.  * Get the list of font fallbacks that the platform-specific code
  3284.  * can use to try to find the closest matching font the name 
  3285.  * requested.
  3286.  *
  3287.  * Results:
  3288.  * As above.
  3289.  *
  3290.  * Side effects:
  3291.  * None.
  3292.  *
  3293.  *-------------------------------------------------------------------------
  3294.  */
  3295. char ***
  3296. TkFontGetFallbacks()
  3297. {
  3298.     return fontFallbacks;
  3299. }
  3300. /*
  3301.  *-------------------------------------------------------------------------
  3302.  *
  3303.  * TkFontGetGlobalClass --
  3304.  *
  3305.  * Get the list of fonts to try if the requested font name does not
  3306.  * exist and no fallbacks for that font name could be used either.
  3307.  * The names in this list are considered preferred over all the other
  3308.  * font names in the system when looking for a last-ditch fallback.
  3309.  *
  3310.  * Results:
  3311.  * As above.
  3312.  *
  3313.  * Side effects:
  3314.  * None.
  3315.  *
  3316.  *-------------------------------------------------------------------------
  3317.  */
  3318. char **
  3319. TkFontGetGlobalClass()
  3320. {
  3321.     return globalFontClass;
  3322. }
  3323. /*
  3324.  *-------------------------------------------------------------------------
  3325.  *
  3326.  * TkFontGetSymbolClass --
  3327.  *
  3328.  * Get the list of fonts that are symbolic; used if the operating 
  3329.  * system cannot apriori identify symbolic fonts on its own.
  3330.  *
  3331.  * Results:
  3332.  * As above.
  3333.  *
  3334.  * Side effects:
  3335.  * None.
  3336.  *
  3337.  *-------------------------------------------------------------------------
  3338.  */
  3339. char **
  3340. TkFontGetSymbolClass()
  3341. {
  3342.     return symbolClass;
  3343. }
  3344. /*
  3345.  *----------------------------------------------------------------------
  3346.  *
  3347.  * TkDebugFont --
  3348.  *
  3349.  * This procedure returns debugging information about a font.
  3350.  *
  3351.  * Results:
  3352.  * The return value is a list with one sublist for each TkFont
  3353.  * corresponding to "name".  Each sublist has two elements that
  3354.  * contain the resourceRefCount and objRefCount fields from the
  3355.  * TkFont structure.
  3356.  *
  3357.  * Side effects:
  3358.  * None.
  3359.  *
  3360.  *----------------------------------------------------------------------
  3361.  */
  3362. Tcl_Obj *
  3363. TkDebugFont(tkwin, name)
  3364.     Tk_Window tkwin; /* The window in which the font will be
  3365.  * used (not currently used). */
  3366.     char *name; /* Name of the desired color. */
  3367. {
  3368.     TkFont *fontPtr;
  3369.     Tcl_HashEntry *hashPtr;
  3370.     Tcl_Obj *resultPtr, *objPtr;
  3371.     resultPtr = Tcl_NewObj();
  3372.     hashPtr = Tcl_FindHashEntry(
  3373.     &((TkWindow *) tkwin)->mainPtr->fontInfoPtr->fontCache, name);
  3374.     if (hashPtr != NULL) {
  3375. fontPtr = (TkFont *) Tcl_GetHashValue(hashPtr);
  3376. if (fontPtr == NULL) {
  3377.     panic("TkDebugFont found empty hash table entry");
  3378. }
  3379. for ( ; (fontPtr != NULL); fontPtr = fontPtr->nextPtr) {
  3380.     objPtr = Tcl_NewObj();
  3381.     Tcl_ListObjAppendElement(NULL, objPtr,
  3382.     Tcl_NewIntObj(fontPtr->resourceRefCount));
  3383.     Tcl_ListObjAppendElement(NULL, objPtr,
  3384.     Tcl_NewIntObj(fontPtr->objRefCount)); 
  3385.     Tcl_ListObjAppendElement(NULL, resultPtr, objPtr);
  3386. }
  3387.     }
  3388.     return resultPtr;
  3389. }
  3390. /*
  3391.  *----------------------------------------------------------------------
  3392.  *
  3393.  * TkFontGetFirstTextLayout --
  3394.  *
  3395.  * This procedure returns the first chunk of a Tk_TextLayout,
  3396.  * i.e. until the first font change on the first line (or the
  3397.  * whole first line if there is no such font change).
  3398.  *
  3399.  * Results:
  3400.  * The return value is the byte length of the chunk, the chunk
  3401.  * itself is copied into dst and its Tk_Font into font.
  3402.  *
  3403.  * Side effects:
  3404.  * None.
  3405.  *
  3406.  *----------------------------------------------------------------------
  3407.  */
  3408. int
  3409. TkFontGetFirstTextLayout(
  3410.     Tk_TextLayout layout, /* Layout information, from a previous call
  3411.  * to Tk_ComputeTextLayout(). */
  3412.     Tk_Font * font,
  3413.     char    * dst)
  3414. {
  3415.     TextLayout  *layoutPtr;
  3416.     LayoutChunk *chunkPtr;
  3417.     int numBytesInChunk;
  3418.     layoutPtr = (TextLayout *)layout;
  3419.     if ((layoutPtr==NULL)
  3420.             || (layoutPtr->numChunks==0)
  3421.             || (layoutPtr->chunks->numDisplayChars <= 0)) {
  3422.         dst[0] = '';
  3423.         return 0;
  3424.     }
  3425.     chunkPtr = layoutPtr->chunks;
  3426.     numBytesInChunk = chunkPtr->numBytes;
  3427.     strncpy(dst, chunkPtr->start, (size_t) numBytesInChunk);
  3428.     *font = layoutPtr->tkfont;
  3429.     return numBytesInChunk;
  3430. }