home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tk42r2s.zip / tk4.2 / os2 / tkOS2Font.c < prev    next >
C/C++ Source or Header  |  1999-07-26  |  44KB  |  1,318 lines

  1. /* 
  2.  * tkOS2Font.c --
  3.  *
  4.  *    This file contains the Xlib emulation routines relating to
  5.  *    creating and manipulating fonts.
  6.  *
  7.  * Copyright (c) 1996-1998 Illya Vaes
  8.  * Copyright (c) 1995 Sun Microsystems, Inc.
  9.  * Copyright (c) 1994 Software Research Associates, 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.  
  15.  
  16. #include "tkOS2Int.h"
  17.  
  18. /*
  19.  * Forward declarations for functions used in this file.
  20.  */
  21. static int        NameToFont (_Xconst char *name, TkOS2Font *logfont);
  22. static int        XNameToFont (_Xconst char *name, TkOS2Font *logfont);
  23.  
  24. /*
  25.  * Code pages used in this file, 1004 is Windows compatible, 65400 must be
  26.  * used if the font contains special glyphs, ie. Symbol.
  27.  */
  28.  
  29. #define CP_LATIN1 850L
  30. #define CP_1004   1004L
  31. #define CP_65400  65400L
  32.  
  33. #ifdef IGNOREPMRES
  34.     /*
  35.      * Shrink 120 to the value of overrideResolution to facilitate 'better'
  36.      * sizing for those displays which report a resolution of 120dpi but have
  37.      * actual resolution close to 96dpi (VGA upto ?800x600?).
  38.      * This is obviously dependent on both resolution and screen size,
  39.      * as higher resolutions usually use 120dpi fonts, regardless of any
  40.      * screen size.
  41.      */
  42.     #define PIXTOPOINT(pixels) ( \
  43.         (aDevCaps[CAPS_VERTICAL_FONT_RES] == 120) \
  44.         ? (((pixels) * 72) / overrideResolution) \
  45.         : (((pixels) * 72) / aDevCaps[CAPS_VERTICAL_FONT_RES]) \
  46.     )
  47.     #define POINTTOPIX(points) ( \
  48.         (aDevCaps[CAPS_VERTICAL_FONT_RES] == 120) \
  49.         ? (((points) * overrideResolution) / 72) \
  50.         : (((points) * aDevCaps[CAPS_VERTICAL_FONT_RES]) / 72) \
  51.     )
  52.     #define PTOP(p) ( \
  53.         (aDevCaps[CAPS_VERTICAL_FONT_RES] == 120) \
  54.         ? (((p) * overrideResolution) / 120 ) \
  55.         : (p) \
  56.     )
  57.     #define FIX_RES(res) (if (res==120) {res = overrideResolution})
  58. #else
  59.     #define PIXTOPOINT(pixels) \
  60.         (((pixels) * 72) / aDevCaps[CAPS_VERTICAL_FONT_RES])
  61.     #define POINTTOPIX(points) \
  62.         (((points) * aDevCaps[CAPS_VERTICAL_FONT_RES]) / 72)
  63.     #define PTOP(p)  (p)
  64.     #define FIX_RES(res)
  65. #endif
  66.  
  67.  
  68. /*
  69.  *----------------------------------------------------------------------
  70.  *
  71.  * NameToFont --
  72.  *
  73.  *    Converts into a logical font description:
  74.  *       - a three part font name of the form:
  75.  *        "Family point_size style_list"
  76.  *         Style_list contains a list of one or more attributes:
  77.  *        normal, bold, italic, underline, strikeout
  78.  *         Point size in decipoints.
  79.  *
  80.  * Results:
  81.  *    Returns false if the font name was syntactically invalid,
  82.  *    else true.  Sets the fields of the passed in TkOS2Font.
  83.  *
  84.  * Side effects:
  85.  *    None.
  86.  *
  87.  *----------------------------------------------------------------------
  88.  */
  89.  
  90. static int
  91. NameToFont(name, logfont)
  92.     _Xconst char *name;
  93.     TkOS2Font *logfont;
  94. {
  95.     int argc, argc2;
  96.     char **argv, **argv2;
  97.     int nameLen, i, pointSize = 0;
  98.  
  99.     if (Tcl_SplitList(NULL, (char *) name, &argc, &argv) != TCL_OK) {
  100.     return False;
  101.     }
  102.     if (argc != 3) {
  103.     ckfree((char *) argv);
  104.     return False;
  105.     }
  106.  
  107.     /*
  108.      * Determine the font family name.
  109.      */
  110.  
  111.     nameLen = strlen(argv[0]);
  112.     if (nameLen > FACESIZE) {
  113.     nameLen = FACESIZE;
  114.     }
  115.     strncpy(logfont->fattrs.szFacename, argv[0], nameLen);
  116.  
  117.     /*
  118.      * Check the character set.
  119.      */
  120.  
  121.     logfont->fattrs.usCodePage = 0;
  122.     if (stricmp(logfont->fattrs.szFacename, "Symbol") == 0) {
  123.     logfont->fattrs.usCodePage = CP_65400;
  124.     } else if (stricmp(logfont->fattrs.szFacename, "Symbol Set") == 0) {
  125.     logfont->fattrs.usCodePage = CP_65400;
  126.     } else if (stricmp(logfont->fattrs.szFacename, "WingDings") == 0) {
  127.     logfont->fattrs.usCodePage = CP_65400;
  128.     } else if (stricmp(logfont->fattrs.szFacename, "ZapfDingbats") == 0) {
  129.     logfont->fattrs.usCodePage = CP_65400;
  130.     } else if (stricmp(logfont->fattrs.szFacename, "StarBats") == 0) {
  131.     logfont->fattrs.usCodePage = CP_65400;
  132.     }
  133.     
  134.     /*
  135.      * Determine the font size.
  136.      */
  137.  
  138.     if (Tcl_GetInt(NULL, argv[1], &pointSize) != TCL_OK) {
  139.     ckfree((char *) argv);
  140.     return False;
  141.     }
  142.     logfont->fattrs.lMaxBaselineExt = POINTTOPIX(pointSize);
  143.     logfont->deciPoints = pointSize;
  144.  
  145.     /*
  146.      * Apply any style modifiers.
  147.      */
  148.     
  149.     if (Tcl_SplitList(NULL, (char *) argv[2], &argc2, &argv2) != TCL_OK) {
  150.     ckfree((char*) argv);
  151.     return False;
  152.     }
  153.     for (i = 0; i < argc2; i++) {
  154.     if (stricmp(argv2[i], "bold") == 0) {
  155.         logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
  156.     } else if (stricmp(argv2[i], "heavy") == 0) {
  157.         logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
  158.     } else if (stricmp(argv2[i], "semibold") == 0) {
  159.         logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
  160.     } else if (stricmp(argv2[i], "extrabold") == 0) {
  161.         logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
  162.     } else if (stricmp(argv2[i], "italic") == 0) {
  163.         logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
  164.     } else if (stricmp(argv2[i], "oblique") == 0) {
  165.         logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
  166.     } else if (stricmp(argv2[i], "underline") == 0) {
  167.         logfont->fattrs.fsSelection |= FATTR_SEL_UNDERSCORE;
  168.     } else if (stricmp(argv2[i], "strikeout") == 0) {
  169.         logfont->fattrs.fsSelection |= FATTR_SEL_STRIKEOUT;
  170.     } else {
  171.         /* ignore for now */
  172.     }
  173.     }
  174.  
  175.     ckfree((char *) argv);
  176.     ckfree((char *) argv2);
  177.     return True;
  178. }
  179.  
  180. /*
  181.  *----------------------------------------------------------------------
  182.  *
  183.  * XNameToFont --
  184.  *
  185.  *    This function constructs a logical font description from an
  186.  *    X font name.  This code only handles font names with all 13
  187.  *    parts, although a part can be '*'.
  188.  *
  189.  * Results:
  190.  *    Returns false if the font name was syntactically invalid,
  191.  *    else true.  Sets the fields of the passed in TkOS2Font.
  192.  *
  193.  * Side effects:
  194.  *    None.
  195.  *
  196.  *----------------------------------------------------------------------
  197.  */
  198.  
  199. static int
  200. XNameToFont(name, logfont)
  201.     _Xconst char *name;
  202.     TkOS2Font *logfont;
  203. {
  204.     const char *head, *tail;
  205.     const char *field[13];
  206.     int flen[13];
  207.     int i, len, togo = 0;
  208.  
  209.     /*
  210.      * Valid font name patterns must have a leading '-' or '*'.
  211.      */
  212.  
  213.     head = tail = name;
  214.     if (*tail == '-') {
  215.     head++; tail++;
  216.     } else if (*tail != '*') {
  217.     return FALSE;
  218.     }
  219.  
  220.     /*
  221.      * Identify field boundaries.  Stores a pointer to the beginning
  222.      * of each field in field[i], and the length of the field in flen[i].
  223.      * Fields are separated by dashes.  Each '*' becomes a field by itself.
  224.      */
  225.  
  226.     i = 0;
  227.     while (*tail != '\0' && i < 12) {
  228.     if (*tail == '-') {
  229.         flen[i] = tail - head;
  230.         field[i] = head;
  231.         tail++;
  232.         head = tail;
  233.         i++;
  234.     } else if (*tail == '*') {
  235.         len = tail - head;
  236.         if (len > 0) {
  237.         flen[i] = tail - head;
  238.         field[i] = head;
  239.         } else {
  240.         flen[i] = 1;
  241.         field[i] = head;
  242.         tail++;
  243.         if (*tail == '-') {
  244.             tail++;
  245.         }
  246.         }
  247.         head = tail;
  248.         i++;
  249.     } else {
  250.         tail++;
  251.     }
  252.     }
  253.  
  254.     /*
  255.      * We handle the last field as a special case, since it may contain
  256.      * an embedded hyphen.
  257.      */
  258.  
  259.     flen[i] = strlen(head);
  260.     field[i] = head;
  261.  
  262.     /*
  263.      * Bail if we don't have at least a font and size.
  264.      */
  265.  
  266.     if (i < 8) {
  267.     return FALSE;
  268.     } 
  269.  
  270. togo=i;
  271.     /*
  272.      * Now fill in the logical font description from the fields we have
  273.      * identified.
  274.      */
  275.  
  276.     /*
  277.      * Field 1: Foundry.  Skip.
  278.      */
  279.     if (--togo <= 0) return TRUE;
  280.  
  281.     /*
  282.      * Field 2: Font Family.
  283.      */
  284.  
  285.     i = 1;
  286.     if (!(flen[i] == 0 ||
  287.       (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
  288.     {
  289.     len = (flen[i] < FACESIZE) ? flen[i] : FACESIZE - 1;
  290.     strncpy(logfont->fattrs.szFacename, field[i], len);
  291.  
  292.     /*
  293.      * Need to handle Symbol fonts specially.
  294.      */
  295.  
  296.     if (stricmp(logfont->fattrs.szFacename, "Symbol") == 0) {
  297.         logfont->fattrs.usCodePage = CP_65400;
  298.         } else if (stricmp(logfont->fattrs.szFacename, "Symbol Set") == 0) {
  299.         logfont->fattrs.usCodePage = CP_65400;
  300.         } else if (stricmp(logfont->fattrs.szFacename, "WingDings") == 0) {
  301.         logfont->fattrs.usCodePage = CP_65400;
  302.         } else if (stricmp(logfont->fattrs.szFacename, "ZapfDingbats") == 0) {
  303.         logfont->fattrs.usCodePage = CP_65400;
  304.         } else if (stricmp(logfont->fattrs.szFacename, "StarBats") == 0) {
  305.         logfont->fattrs.usCodePage = CP_65400;
  306.     }
  307.     }
  308.     if (--togo <= 0) return TRUE;
  309.  
  310.     /*
  311.      * Field 3: Weight.  Default is medium.
  312.      */
  313.  
  314.     i = 2;
  315.     if ((flen[i] > 0) && (strnicmp(field[i], "bold", flen[i]) == 0)) {
  316.     logfont->fattrs.fsSelection |= FATTR_SEL_BOLD;
  317.     } else {
  318.     logfont->fattrs.fsSelection &= ~FATTR_SEL_BOLD;
  319.     }
  320.     if (--togo <= 0) return TRUE;
  321.         
  322.     /*
  323.      * Field 4: Slant.  Default is Roman.
  324.      */
  325.     
  326.     i = 3;
  327.     if (!(flen[i] == 0 ||
  328.       (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
  329.     {
  330.     if (strnicmp(field[i], "r", flen[i]) == 0) {
  331.         /* Roman. */
  332.         logfont->fattrs.fsSelection &= ~FATTR_SEL_ITALIC;
  333.     } else if (strnicmp(field[i], "i", flen[i]) == 0) {
  334.         /* Italic */
  335.         logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
  336.     } else if (strnicmp(field[i], "o", flen[i]) == 0) {
  337.         /* Oblique, set to 15 degree slant forward */
  338.         logfont->shear.x = 2588;    /* 10000*cos(75) */
  339.         logfont->shear.y = 9659;    /* 10000*sin(75) */
  340.         logfont->setShear = TRUE;
  341.         logfont->fattrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
  342.             logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
  343.     } else if (strnicmp(field[i], "ri", flen[i]) == 0) {
  344.         /* Reverse Italic, set to 30 degree slant backward */
  345.         logfont->shear.x = -5000;    /* 10000*cos(120) */
  346.         logfont->shear.y = 8660;    /* 10000*sin(120) */
  347.         logfont->setShear = TRUE;
  348.         logfont->fattrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
  349.             logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
  350.     } else if (strnicmp(field[i], "ro", flen[i]) == 0) {
  351.         /* Reverse Oblique, set to 15 degree slant backward */
  352.         logfont->shear.x = -2588;    /* 10000*cos(105) */
  353.         logfont->shear.y = 9659;    /* 10000*sin(105) */
  354.         logfont->setShear = TRUE;
  355.         logfont->fattrs.fsFontUse |= FATTR_FONTUSE_TRANSFORMABLE;
  356.             logfont->fattrs.fsSelection |= FATTR_SEL_ITALIC;
  357.     } else if (strnicmp(field[i], "ot", flen[i]) == 0) {
  358.         /* Other */
  359.     } else {
  360.         return FALSE;
  361.     }
  362.     }
  363.     if (--togo <= 0) return TRUE;
  364.  
  365.     /*
  366.      * Field 5 & 6: Set Width & Blank.  Skip.
  367.      */
  368.     if (--togo <= 0) return TRUE;
  369.  
  370.     /*
  371.      * Field 7: Pixels.  Use this as the points if no points set.
  372.      */
  373.     if (--togo <= 0) return TRUE;
  374.  
  375.     i = 6;
  376.     if (!(flen[i] == 0 ||
  377.       (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
  378.     {
  379.         logfont->fattrs.lMaxBaselineExt = atoi(field[i]);
  380.         /* Points is  (pixels * 72) / FONT_RES ; Note: decipixels! */
  381.         logfont->deciPoints = PIXTOPOINT(logfont->fattrs.lMaxBaselineExt * 10);
  382.  
  383.     }
  384.     if (--togo <= 0) return TRUE;
  385.  
  386.     /*
  387.      * Field 8: Points in tenths of a point.
  388.      */
  389.  
  390.     i = 7;
  391.     if (!(flen[i] == 0 ||
  392.       (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
  393.     {
  394.         logfont->deciPoints = atoi(field[i]);
  395.         logfont->fattrs.lMaxBaselineExt = POINTTOPIX(logfont->deciPoints) / 10;
  396.     }
  397.     if (--togo <= 0) return TRUE;
  398.  
  399.     /*
  400.      * Field 9: Horizontal Resolution in DPI.  Skip.
  401.      * Field 10: Vertical Resolution in DPI.  Skip.
  402.      */
  403.     if (--togo <= 0) return TRUE;
  404.  
  405.     /*
  406.      * Field 11: Spacing.
  407.      * we can't request this via PM's TkOS2Font, so skip.
  408.      */
  409.     if (--togo <= 0) return TRUE;
  410.  
  411.     /*
  412.      * Field 12: Average Width.
  413.      * Width should be 0 for outline fonts.
  414.      */
  415.  
  416.     i = 11;
  417.     if (!(flen[i] == 0 ||
  418.          (flen[i] == 1 && (field[i][0] == '*' || field[i][0] == '?'))))
  419.     {
  420.         logfont->fattrs.lAveCharWidth = (atoi(field[i]) / 10);
  421.     }
  422.     if (--togo <= 0) return TRUE;
  423.  
  424.     /*
  425.      * Field 13: Character Set.  Skip.
  426.      */
  427.     if (--togo <= 0) return TRUE;
  428.  
  429.     return TRUE;
  430. }
  431.  
  432. /*
  433.  *----------------------------------------------------------------------
  434.  *
  435.  * XLoadFont --
  436.  *
  437.  *    Get the font handle for the specified font.
  438.  *    Also handles:
  439.  *       - a "Presentation Parameter"-style specification
  440.  *        "pixelsize.fontname[.attr][.attr][.attr][.attr][.attr]"
  441.  *         Each attr one of bold, italic, underline, strikeout, outline.
  442.  *
  443.  * Results:
  444.  *    Returns the font handle.
  445.  *
  446.  * Side effects:
  447.  *    None.
  448.  *
  449.  *----------------------------------------------------------------------
  450.  */
  451.  
  452. Font
  453. XLoadFont(display, name)
  454.     Display* display;
  455.     _Xconst char* name;
  456. {
  457.     LONG lFontID= nextLogicalFont;
  458.     LONG match = 0;
  459.     PFONTMETRICS os2fonts;
  460.     LONG reqFonts, remFonts;
  461.     BOOL found = FALSE;
  462.     /* Use nominal size unless given Presentation Parameter style spec. */
  463.     /*
  464.     BOOL useIntended = TRUE;
  465.     */
  466.     BOOL useIntended = FALSE;
  467.     LONG outline = -1;
  468.     LONG font = 0;
  469.     int i, error = 30000, best = -1;
  470.  
  471.     if (lFontID > MAX_LID) {
  472.         /* We can't simultaneously  use more than MAX_LID fonts */
  473.         return (Font) 0;
  474.     }
  475.  
  476.     /* Set defaults in logfont */
  477.     logfonts[lFontID].fattrs.usRecordLength = (USHORT)sizeof(FATTRS);
  478.     logfonts[lFontID].fattrs.fsSelection = (USHORT)0;
  479.     logfonts[lFontID].fattrs.lMatch = 0L;
  480.     memset(logfonts[lFontID].fattrs.szFacename, '\0', FACESIZE);
  481.     logfonts[lFontID].fattrs.idRegistry = 0;    /* Unknown */
  482.     logfonts[lFontID].fattrs.usCodePage = 0;    /* Use present codepage */
  483.     logfonts[lFontID].fattrs.lMaxBaselineExt = 0L;    /* 0 for vector fonts */
  484.     logfonts[lFontID].fattrs.lAveCharWidth = 0L;    /* 0 for vector fonts */
  485.     logfonts[lFontID].fattrs.fsType = 0;
  486.     logfonts[lFontID].fattrs.fsFontUse = 0;
  487.     logfonts[lFontID].shear.x = 0;
  488.     logfonts[lFontID].shear.y = 1;    /* Upright characters by default */
  489.     /* Not necessary to set shear by default */
  490.     logfonts[lFontID].setShear = FALSE;
  491.     logfonts[lFontID].outline = FALSE;
  492.     logfonts[lFontID].deciPoints = 120;
  493.     logfonts[lFontID].fattrs.lMaxBaselineExt = 12;
  494.  
  495.     if (! (((name[0] == '-') || (name[0] == '*')) &&
  496.          XNameToFont(name, &logfonts[lFontID]))) {
  497.         if (!NameToFont(name, &logfonts[lFontID])) {
  498.             /* Our own (non-X) fonts, recognize Windows fontnames for
  499.              * compatibility of scripts.
  500.              */
  501.     
  502.             if ((stricmp(name, "system") == 0) ||    /* OS/2 and Windows font */
  503.                 (stricmp(name, "device") == 0)) {    /* Windows font */
  504.                 strncpy(logfonts[lFontID].fattrs.szFacename, "System VIO", 10);
  505.             } else if ((strnicmp(name, "systemmonospaced", 16) == 0) ||
  506.                        (strnicmp(name, "ansifixed", 9) == 0) ||    /* Windows font */
  507.                        (strnicmp(name, "systemfixed", 11) == 0) ||  /* Windows font */
  508.                        (strnicmp(name, "oemfixed", 8) == 0)) {    /* Windows font */
  509.                 strncpy(logfonts[lFontID].fattrs.szFacename, "System Monospaced", 17);
  510.             } else if ((strnicmp(name, "systemproportional", 18) == 0) ||
  511.                        (strnicmp(name, "ansi", 4) == 0)) {    /* Windows font */
  512.                 strncpy(logfonts[lFontID].fattrs.szFacename, "System Proportional", 19);
  513.             } else {
  514.                 /*
  515.                  * The following code suggested by Ilya Zakharevich.
  516.                  * Its use is to allow font selection "in OS/2-style", like
  517.                  * "10.Courier".
  518.                  * Ilya's way of supplying attributes of the font is against
  519.                  * the documented "pointSize.Fontname[.attr ...]" though,
  520.                  * because it gives attributes between the pointsize and the
  521.                  * name of the font.
  522.                  * I take the "official" stance and also supply the rest of the
  523.                  * font Presentation Parameters: underline, strikeout, outline.
  524.                  */
  525.                 int l, off = 0;
  526.  
  527.                 if (sscanf(name, "%d.%n", &l, &off) && off > 0) {
  528.                     int fields;
  529.                     /*
  530.                     logfonts[lFontID].fattrs.lMaxBaselineExt = POINTTOPIX(l);
  531.                     logfonts[lFontID].deciPoints = l * 10;
  532.                     */
  533.                     logfonts[lFontID].fattrs.lMaxBaselineExt = l;
  534.                     logfonts[lFontID].deciPoints = PIXTOPOINT(l * 10);
  535.                     name += off;
  536.                     useIntended = TRUE;
  537.                     /* Get the fontname out */
  538.                     fields = sscanf(name, "%[^.]%n",
  539.                                    (char *)&logfonts[lFontID].fattrs.szFacename,
  540.                                    &off);
  541.                     if (fields==1 && strlen(name)==off) {
  542.                         /* Fontname is last part */
  543.                         l = strlen(name);
  544.                         if (l > FACESIZE - 1) {
  545.                             l = FACESIZE - 1;
  546.                         }
  547.                         strncpy(logfonts[lFontID].fattrs.szFacename, name, l);
  548.                     } else {
  549.                         /* There are attributes after the fontname */
  550.                         name += off;
  551.                         while (TRUE) {
  552.                             if (strnicmp(name, ".bold", 5) == 0) {
  553.                                 logfonts[lFontID].fattrs.fsSelection
  554.                                     |= FATTR_SEL_BOLD;
  555.                                 name += 5;
  556.                             } else if (strnicmp(name, ".italic", 7) == 0) {
  557.                                 logfonts[lFontID].fattrs.fsSelection
  558.                                     |= FATTR_SEL_ITALIC;
  559.                                 name += 7;
  560.                             } else if (strnicmp(name, ".underline", 10) == 0) {
  561.                                 logfonts[lFontID].fattrs.fsSelection
  562.                                     |= FATTR_SEL_UNDERSCORE;
  563.                                 name += 10;
  564.                             } else if (strnicmp(name, ".strikeout", 10) == 0) {
  565.                                 logfonts[lFontID].fattrs.fsSelection
  566.                                     |= FATTR_SEL_STRIKEOUT;
  567.                                 name += 10;
  568.                             } else if (strnicmp(name, ".outline", 8) == 0) {
  569.                                 logfonts[lFontID].fattrs.fsSelection
  570.                                     |= FATTR_SEL_OUTLINE;
  571.                                 name += 8;
  572.                             } else if (*name == '.') {
  573.                                 name++;
  574.                                 break;
  575.                             } else {
  576.                                 break;
  577.                             }
  578.                         }
  579.                     }
  580.                 } else {
  581.                     l = strlen(name);
  582.                     if (l > FACESIZE - 1) {
  583.                         l = FACESIZE - 1;
  584.                     }
  585.                     strncpy(logfonts[lFontID].fattrs.szFacename, name, l);
  586.                 }
  587.             }
  588.         }
  589.     }
  590.     /* Name has now been filled in with a correct or sane value */
  591.     /* Determine number of fonts */
  592.     reqFonts = 0L;
  593.     remFonts = GpiQueryFonts(globalPS, QF_PUBLIC,
  594.                              logfonts[lFontID].fattrs.szFacename, &reqFonts,
  595.                              (LONG) sizeof(FONTMETRICS), NULL);
  596.     reqFonts = remFonts;
  597.     if (reqFonts) {
  598.         /* Allocate space for the fonts */
  599.         os2fonts = (PFONTMETRICS) ckalloc(remFonts * sizeof(FONTMETRICS));
  600.         if (os2fonts == NULL) {
  601.             return (Font) 0;
  602.         }
  603.         /* Get the fonts that apply */
  604.         remFonts = GpiQueryFonts(globalPS, QF_PUBLIC,
  605.                                  logfonts[lFontID].fattrs.szFacename, &reqFonts,
  606.                                  (LONG) sizeof(FONTMETRICS), os2fonts);
  607.     } else {
  608.         os2fonts = NULL;
  609.     }
  610.     /*
  611.      * Determine the one that has the right size, preferring a bitmap font over
  612.      * a scalable (outline) one if it exists.
  613.      */
  614.     for (i=0; i<reqFonts && !found; i++) {
  615.         /*
  616.          * Note: scalable fonts appear to always return lEmHeight 16, so first
  617.          * check for outline, then "point size" to not match on size 16.
  618.          */
  619.         if (os2fonts[i].fsDefn & FM_DEFN_OUTLINE) {
  620.             /* Remember we found an outline font */
  621.             outline = i;
  622.         } else {
  623.             /* Bitmap font, check size, type, resolution */
  624.             int cerror = 0, err1;
  625.  
  626.             /*
  627.              * Note: FONTMETRICS.fsSelection can contain FM_SEL_ISO9241_TESTED,
  628.              * FATTRS.fsSelection cannot.
  629.              */
  630. /*
  631.             if (
  632.                 ((useIntended ? os2fonts[i].sNominalPointSize :
  633.                                 (os2fonts[i].lMaxBaselineExt * 10)) ==
  634.                        logfonts[lFontID].fattrs.lMaxBaselineExt * 10)
  635. */
  636.             /* If we need a transformable font, we *need* an outline */
  637. /*
  638.                 &&
  639.         (!(logfonts[lFontID].fattrs.fsFontUse & FATTR_FONTUSE_TRANSFORMABLE))
  640.                 &&
  641.                 (os2fonts[i].sXDeviceRes == aDevCaps[CAPS_HORIZONTAL_FONT_RES])
  642.                 &&
  643.                 (os2fonts[i].sYDeviceRes == aDevCaps[CAPS_VERTICAL_FONT_RES])
  644.                 ) {
  645.                 found = TRUE;
  646.                 match = os2fonts[i].lMatch;
  647.                 font = i;
  648. */
  649.             err1 = ( useIntended ? os2fonts[i].sNominalPointSize
  650.                                  : (os2fonts[i].lMaxBaselineExt * 10))
  651.                      - logfonts[lFontID].fattrs.lMaxBaselineExt * 10;
  652.             if (err1 < 0) {
  653.                 err1 = -err1;
  654.             }
  655.             cerror = err1;
  656.             if (logfonts[lFontID].fattrs.lAveCharWidth) {
  657.                 err1 = logfonts[lFontID].fattrs.lAveCharWidth
  658.                        - os2fonts[i].lAveCharWidth;
  659.                 if (err1 < 0) {
  660.                     err1 = -err1;
  661.                 }
  662.                 cerror += err1 * 3;    /* 10/3 times cheaper */
  663.             }
  664.             if (os2fonts[i].sXDeviceRes != aDevCaps[CAPS_HORIZONTAL_FONT_RES] ||
  665.                 os2fonts[i].sYDeviceRes != aDevCaps[CAPS_VERTICAL_FONT_RES]) {
  666.                 cerror += 1;
  667.             }
  668.             if (cerror < error) {
  669.                 error = cerror;
  670.                 best = i;
  671.             }
  672.             if (cerror == 0) {
  673.                 found = TRUE;
  674.                 font = best;
  675.                 match = os2fonts[best].lMatch;
  676.             }
  677.         }
  678.     }
  679.     /* If an exact bitmap for a different resolution found, take it */
  680.     if (!found && error <= 1) {
  681.         match = os2fonts[best].lMatch;
  682.         font = best;
  683.         found = TRUE;
  684.     }
  685.     /* If no bitmap but an outline found, take it */
  686.     if (!found && outline != -1) {
  687.         match = os2fonts[outline].lMatch;
  688.         font = outline;
  689.         found = TRUE;
  690.         logfonts[lFontID].outline = TRUE;
  691.     }
  692.     /* If no exact bitmap but an approximate found, take it */
  693.     if (!found && best != -1) {
  694.         match = os2fonts[best].lMatch;
  695.         font = best;
  696.         found = TRUE;
  697.     }
  698.     if (!found) {
  699.     /* Select default font by making facename empty */
  700.         memset(logfonts[lFontID].fattrs.szFacename, '\0', FACESIZE);
  701.         match= GpiCreateLogFont(globalPS, NULL, lFontID,
  702.                                 &(logfonts[lFontID].fattrs));
  703.         if (match == GPI_ERROR) {
  704.             if (os2fonts) {
  705.                 ckfree((char *)os2fonts);
  706.             }
  707.             return (Font) 0;
  708.         } else if (match == FONT_DEFAULT) {
  709.             FONTMETRICS fm;
  710.             rc= GpiQueryFontMetrics(globalPS, sizeof(FONTMETRICS), &fm);
  711.             if (!rc) {
  712.                 return (Font) 0;
  713.             }
  714.             logfonts[lFontID].fattrs.lMatch = 0;
  715.             strcpy(logfonts[lFontID].fattrs.szFacename, fm.szFacename);
  716.             logfonts[lFontID].fattrs.idRegistry = fm.idRegistry;
  717.             logfonts[lFontID].fattrs.usCodePage = fm.usCodePage;
  718.             logfonts[lFontID].fattrs.lMaxBaselineExt = fm.lMaxBaselineExt;
  719.             logfonts[lFontID].fattrs.lAveCharWidth = fm.lAveCharWidth;
  720.             logfonts[lFontID].fattrs.fsType = 0;
  721.             logfonts[lFontID].fattrs.fsFontUse = 0;
  722.             goto got_it;
  723.         }
  724.     }
  725.     /* Fill in the exact font metrics if we found a font */
  726.     if (!found) {
  727.         if (os2fonts) {
  728.             ckfree((char *)os2fonts);
  729.         }
  730.         return (Font) 0;
  731.     } else {
  732.         logfonts[lFontID].fattrs.idRegistry = os2fonts[font].idRegistry;
  733.         logfonts[lFontID].fattrs.lMatch = match;
  734.         strcpy(logfonts[lFontID].fattrs.szFacename, os2fonts[font].szFacename);
  735.         if (os2fonts[font].fsDefn & FM_DEFN_OUTLINE) {
  736.             logfonts[lFontID].fattrs.lMaxBaselineExt = 0;
  737.             logfonts[lFontID].fattrs.lAveCharWidth = 0;
  738.             logfonts[lFontID].fattrs.fsFontUse |= FATTR_FONTUSE_OUTLINE;
  739.         } else {
  740.             logfonts[lFontID].fattrs.lMaxBaselineExt =
  741.                               os2fonts[font].lMaxBaselineExt;
  742.             logfonts[lFontID].fattrs.lAveCharWidth =
  743.                               os2fonts[font].lAveCharWidth;
  744.         }
  745.     }
  746.  
  747. got_it:
  748.  
  749.     match = GpiCreateLogFont(globalPS, NULL, lFontID,
  750.                              &(logfonts[lFontID].fattrs));
  751.     if (match == GPI_ERROR) {
  752.     /* Select default font by making facename empty */
  753.         memset(logfonts[lFontID].fattrs.szFacename, '\0', FACESIZE);
  754.         match = GpiCreateLogFont(globalPS, NULL, lFontID,
  755.                                  &(logfonts[lFontID].fattrs));
  756.     }
  757.     /* Scale the font to the right size if outline font */
  758.     if (logfonts[lFontID].outline) {
  759.         rc = TkOS2ScaleFont(globalPS, logfonts[lFontID].deciPoints, 0);
  760.     }
  761.  
  762.     if (match == GPI_ERROR) {
  763.         if (os2fonts) {
  764.             ckfree((char *)os2fonts);
  765.         }
  766.         return (Font) 0;
  767.     } else {
  768.         ckfree((char *)os2fonts);
  769.         nextLogicalFont++;
  770.         return (Font) lFontID;
  771.     }
  772. }
  773.  
  774. /*
  775.  *----------------------------------------------------------------------
  776.  *
  777.  * XQueryFont --
  778.  *
  779.  *    Retrieve information about the specified font.
  780.  *
  781.  * Results:
  782.  *    Returns a newly allocated XFontStruct.
  783.  *
  784.  * Side effects:
  785.  *    None.
  786.  *
  787.  *----------------------------------------------------------------------
  788.  */
  789.  
  790. XFontStruct *
  791. XQueryFont(display, font_ID)
  792.     Display* display;
  793.     XID font_ID;
  794. {
  795.     XFontStruct *fontPtr = (XFontStruct *) ckalloc(sizeof(XFontStruct));
  796.     LONG oldFont;
  797.     FONTMETRICS fm;
  798.     XCharStruct bounds;
  799.     BOOL rc;
  800.     POINTL noShear= {0, 1};
  801.  
  802.     if (!fontPtr) {
  803.     return NULL;
  804.     }
  805.     
  806.     fontPtr->fid = font_ID;
  807.  
  808.     oldFont = GpiQueryCharSet(globalPS);
  809.     rc = GpiSetCharSet(globalPS, (LONG) fontPtr->fid);
  810.     /* Set slant if necessary */
  811.     if (logfonts[(LONG)fontPtr->fid].setShear) {
  812.         GpiSetCharShear(globalPS, &(logfonts[(LONG)fontPtr->fid].shear));
  813.     }
  814.  
  815.     /*
  816.      * Determine the font metrics and store the values into the appropriate
  817.      * X data structures.
  818.      */
  819.  
  820.     /* If this is an outline font, set the char box */
  821.     if (logfonts[font_ID].outline) {
  822.         rc = TkOS2ScaleFont(globalPS, logfonts[font_ID].deciPoints, 0);
  823.     }
  824.  
  825.     if (GpiQueryFontMetrics(globalPS, sizeof(FONTMETRICS), &fm)) {
  826.         /*
  827.          * Copy fontmetrics into own structure, so we remember scalable font
  828.          * modifications.
  829.          */
  830.         memcpy((void *)&logfonts[font_ID].fm, (void *)&fm, sizeof(FONTMETRICS));
  831.  
  832.     fontPtr->direction =
  833.                  LOBYTE(fm.sInlineDir) < 90 || LOBYTE(fm.sInlineDir) > 270
  834.              ? FontLeftToRight : FontRightToLeft;
  835.     fontPtr->min_byte1 = 0;
  836.     fontPtr->max_byte1 = 0;
  837.     fontPtr->min_char_or_byte2 = fm.sFirstChar;
  838.     /* sLastChar is *offset* from sFirstChar! */
  839.     fontPtr->max_char_or_byte2 = fm.sFirstChar + fm.sLastChar;
  840.     fontPtr->all_chars_exist = True;
  841.     fontPtr->default_char = fm.sDefaultChar;
  842.     fontPtr->n_properties = 0;
  843.     fontPtr->properties = NULL;
  844.     bounds.lbearing = 0;
  845.     bounds.rbearing = (short) fm.lMaxCharInc;
  846.     bounds.width = (short) fm.lMaxCharInc;
  847.     bounds.ascent = (short) fm.lMaxAscender;
  848.     bounds.descent = (short) fm.lMaxDescender;
  849.     bounds.attributes = 0;
  850.     fontPtr->ascent = fm.lMaxAscender;
  851.     fontPtr->descent = fm.lMaxDescender;
  852.     fontPtr->min_bounds = bounds;
  853.     fontPtr->max_bounds = bounds;
  854.  
  855.     /*
  856.      * If the font is not fixed pitch, then we need to construct
  857.      * the per_char array.
  858.      */
  859.  
  860.     if ( !(fm.fsType & FM_TYPE_FIXED) ) {
  861.         int i;
  862.         char c;
  863.             /*
  864.              * sLastChar is offset from sFirstChar
  865.              * Only 256 code points (0 - 255) allowed in a code page.
  866.              */
  867.         int nchars = MIN(((int)fm.sLastChar + 1), 255);
  868.         int minWidth = 30000;
  869. POINTL endPoint[2];
  870.             PLONG widths;
  871.         fontPtr->per_char =
  872.         (XCharStruct *)ckalloc(sizeof(XCharStruct) * nchars);
  873.  
  874.             /*
  875.              * GpiQueryCharStringPos seems to be more precise than
  876.              * GpiQueryWidthTable. In the widget demo, the first only exhibits
  877.              * some "dancing" when highlighting, while the latter gives a very
  878.              * noticeable space before the cursor.
  879.              * On the other hand, it is abysmal for raster fonts.
  880.              */
  881.             if (logfonts[font_ID].outline) {
  882.                 for (i = 0, c = fm.sFirstChar; i < nchars ; i++, c++ ) {
  883.                     GpiQueryCharStringPos(globalPS, 0L, 1, &c, NULL, endPoint);
  884.                     fontPtr->per_char[i].width = endPoint[1].x - endPoint[0].x;
  885.                     if (minWidth > fontPtr->per_char[i].width) {
  886.                         minWidth = fontPtr->per_char[i].width;
  887.                     }
  888.                 }
  889.             } else {
  890.                 /* Bitmap -> use GpiQueryWidthTable */
  891.                 widths = (PLONG) ckalloc(sizeof(LONG)*nchars);
  892.                 if (widths != NULL) {
  893.                     rc= GpiQueryWidthTable(globalPS, fm.sFirstChar, nchars,
  894.                                            widths);
  895.                     if (rc == TRUE) {
  896.                         for (i = 0; i < nchars ; i++) {
  897.                             fontPtr->per_char[i] = bounds;
  898.                             fontPtr->per_char[i].width = widths[i];
  899.                             if (minWidth > fontPtr->per_char[i].width) {
  900.                                 minWidth = fontPtr->per_char[i].width;
  901.                             }
  902.                         }
  903.                     } else {
  904.                         ckfree((char *)fontPtr);
  905.                         fontPtr = NULL;
  906.                     }
  907.                 } else {
  908.                     ckfree((char *)fontPtr);
  909.                     fontPtr = NULL;
  910.                     goto restore;
  911.                 }
  912.             }
  913.  
  914.         fontPtr->min_bounds.width = minWidth;
  915.     } else {
  916.         fontPtr->per_char = NULL;
  917.     }
  918.     } else {
  919.     ckfree((char *)fontPtr);
  920.     fontPtr = NULL;
  921.     }    
  922.  
  923. restore:
  924.  
  925.     /* Restore font */
  926.     if (logfonts[(LONG)fontPtr->fid].setShear) {
  927.         GpiSetCharShear(globalPS, &noShear);
  928.     }
  929.     GpiSetCharSet(globalPS, oldFont);
  930.     
  931.     return fontPtr;
  932. }
  933.  
  934. /*
  935.  *----------------------------------------------------------------------
  936.  *
  937.  * XLoadQueryFont --
  938.  *
  939.  *    Finds the closest available OS/2 font for the specified
  940.  *    font name.
  941.  *
  942.  * Results:
  943.  *    Allocates and returns an XFontStruct containing a description
  944.  *    of the matching font.
  945.  *
  946.  * Side effects:
  947.  *    None.
  948.  *
  949.  *----------------------------------------------------------------------
  950.  */
  951.  
  952. XFontStruct *
  953. XLoadQueryFont(display, name)
  954.     Display* display;
  955.     _Xconst char* name;
  956. {
  957.     Font font;
  958.  
  959.     font = XLoadFont(display, name);
  960.     return XQueryFont(display, font);
  961. }
  962.  
  963. /*
  964.  *----------------------------------------------------------------------
  965.  *
  966.  * XFreeFont --
  967.  *
  968.  *    Releases resources associated with the specified font.
  969.  *
  970.  * Results:
  971.  *    None.
  972.  *
  973.  * Side effects:
  974.  *    Frees the memory referenced by font_struct.
  975.  *
  976.  *----------------------------------------------------------------------
  977.  */
  978.  
  979. void
  980. XFreeFont(display, font_struct)
  981.     Display* display;
  982.     XFontStruct* font_struct;
  983. {
  984.     /* Only deleting the last ID can be done in this array-approach */
  985.     if (nextLogicalFont-1 == (LONG)font_struct->fid) {
  986.         GpiDeleteSetId(globalPS, (LONG)font_struct->fid);
  987.         nextLogicalFont--;
  988.     }
  989.     if (font_struct->per_char != NULL) {
  990.         ckfree((char *) font_struct->per_char);
  991.     }
  992.     ckfree((char *) font_struct);
  993. }
  994.  
  995. /*
  996.  *----------------------------------------------------------------------
  997.  *
  998.  * XTextWidth --
  999.  *
  1000.  *    Compute the width of an 8-bit character string.
  1001.  *
  1002.  * Results:
  1003.  *    Returns the computed width of the specified string.
  1004.  *
  1005.  * Side effects:
  1006.  *    None.
  1007.  *
  1008.  *----------------------------------------------------------------------
  1009.  */
  1010.  
  1011. int
  1012. XTextWidth(font_struct, string, count)
  1013.     XFontStruct* font_struct;
  1014.     _Xconst char* string;
  1015.     int count;
  1016. {
  1017.     /*
  1018.     FONTMETRICS fm;
  1019.     */
  1020.     LONG oldFont;
  1021.     POINTL aSize[TXTBOX_COUNT];
  1022.     POINTL noShear= {0, 1};
  1023.  
  1024.     oldFont = GpiQueryCharSet(globalPS);
  1025.     GpiSetCharSet(globalPS, (LONG) font_struct->fid);
  1026.     /* Set slant if necessary */
  1027.     if (logfonts[(LONG)font_struct->fid].setShear) {
  1028.         GpiSetCharShear(globalPS, &(logfonts[(LONG)font_struct->fid].shear));
  1029.     }
  1030.     /* If this is an outline font, set the char box */
  1031.     if (logfonts[(LONG)font_struct->fid].outline) {
  1032.         rc = TkOS2ScaleFont(globalPS,
  1033.                             logfonts[(LONG)font_struct->fid].deciPoints, 0);
  1034.     } else {
  1035.         /*
  1036.          * XTextWidth is only used by Tk as an average number, for '0'
  1037.          * -> use lAveCharWidth
  1038.          */
  1039.         return logfonts[(LONG)font_struct->fid].fattrs.lAveCharWidth;
  1040.     }
  1041.  
  1042.     GpiQueryTextBox(globalPS, count, (PCH)string, TXTBOX_COUNT, aSize);
  1043.     /* OS/2 PM does not have ths overhang
  1044.      * GpiQueryFontMetrics(globalPS, sizeof(FONTMETRICS), &fm);
  1045.      * size.cx -= fm.fmOverhang;
  1046.      */
  1047.  
  1048.     /* Restore font */
  1049.     if (logfonts[(LONG)font_struct->fid].setShear) {
  1050.         GpiSetCharShear(globalPS, &noShear);
  1051.     }
  1052.     GpiSetCharSet(globalPS, oldFont);
  1053.  
  1054.     return aSize[TXTBOX_BOTTOMRIGHT].x - aSize[TXTBOX_BOTTOMLEFT].x;
  1055. }
  1056.  
  1057. /*
  1058.  *----------------------------------------------------------------------
  1059.  *
  1060.  * XTextExtents --
  1061.  *
  1062.  *    Compute the bounding box for a string.
  1063.  *
  1064.  * Results:
  1065.  *    Sets the direction_return, ascent_return, descent_return, and
  1066.  *    overall_return values as defined by Xlib.
  1067.  *
  1068.  * Side effects:
  1069.  *    None.
  1070.  *
  1071.  *----------------------------------------------------------------------
  1072.  */
  1073.  
  1074. void
  1075. XTextExtents(font_struct, string, nchars, direction_return,
  1076.     font_ascent_return, font_descent_return, overall_return)
  1077.     XFontStruct* font_struct;
  1078.     _Xconst char* string;
  1079.     int nchars;
  1080.     int* direction_return;
  1081.     int* font_ascent_return;
  1082.     int* font_descent_return;
  1083.     XCharStruct* overall_return;
  1084. {
  1085.     LONG oldFont;
  1086.     POINTL aSize[TXTBOX_COUNT];
  1087.     POINTL noShear= {0, 1};
  1088.  
  1089.     *direction_return = font_struct->direction;
  1090.     *font_ascent_return = font_struct->ascent;
  1091.     *font_descent_return = font_struct->descent;
  1092.  
  1093.     oldFont = GpiQueryCharSet(globalPS);
  1094.     GpiSetCharSet(globalPS, (LONG) font_struct->fid);
  1095.     /* Set slant if necessary */
  1096.     if (logfonts[(LONG)font_struct->fid].setShear) {
  1097.         GpiSetCharShear(globalPS, &(logfonts[(LONG)font_struct->fid].shear));
  1098.     }
  1099.     /* If this is an outline font, set the char box */
  1100.     if (logfonts[(LONG)font_struct->fid].outline) {
  1101.         rc = TkOS2ScaleFont(globalPS,
  1102.                             logfonts[(LONG)font_struct->fid].deciPoints, 0);
  1103.     }
  1104.  
  1105.     overall_return->ascent = (short) 
  1106.                              logfonts[(LONG)font_struct->fid].fm.lMaxAscender;
  1107.     overall_return->descent = (short) 
  1108.                               logfonts[(LONG)font_struct->fid].fm.lMaxDescender;
  1109.     GpiQueryTextBox(globalPS, nchars, (char *)string, TXTBOX_COUNT, aSize);
  1110.     overall_return->width = (short) aSize[TXTBOX_BOTTOMRIGHT].x -
  1111.                             aSize[TXTBOX_BOTTOMLEFT].x;
  1112.     overall_return->lbearing = 0;
  1113.     overall_return->rbearing = (short) overall_return->width;
  1114.  
  1115.     /* Restore font */
  1116.     if (logfonts[(LONG)font_struct->fid].setShear) {
  1117.         GpiSetCharShear(globalPS, &noShear);
  1118.     }
  1119.     GpiSetCharSet(globalPS, oldFont);
  1120. }
  1121.  
  1122. /*
  1123.  *----------------------------------------------------------------------
  1124.  *
  1125.  * XGetFontProperty --
  1126.  *
  1127.  *    Called to get font properties.
  1128.  *
  1129.  * Results:
  1130.  *    Return true for known properties, false otherwise
  1131.  *
  1132.  * Side effects:
  1133.  *    None.
  1134.  *
  1135.  *----------------------------------------------------------------------
  1136.  */
  1137.  
  1138. Bool
  1139. XGetFontProperty(font_struct, atom, value_return)
  1140.     XFontStruct* font_struct;
  1141.     Atom atom;
  1142.     unsigned long* value_return;
  1143. {
  1144.     FONTMETRICS fm;
  1145.  
  1146.     switch (atom) {
  1147.         case XA_SUPERSCRIPT_X:
  1148.             *value_return = (unsigned long)
  1149.                    logfonts[(LONG)font_struct->fid].fm.lSuperscriptXOffset;
  1150.             return True;
  1151.             break;
  1152.         case XA_SUPERSCRIPT_Y:
  1153.             *value_return = (unsigned long)
  1154.                    logfonts[(LONG)font_struct->fid].fm.lSuperscriptYOffset;
  1155.             return True;
  1156.             break;
  1157.         case XA_SUBSCRIPT_X:
  1158.             *value_return = (unsigned long)
  1159.                    logfonts[(LONG)font_struct->fid].fm.lSubscriptXOffset;
  1160.             return True;
  1161.             break;
  1162.         case XA_SUBSCRIPT_Y:
  1163.             *value_return = (unsigned long)
  1164.                    logfonts[(LONG)font_struct->fid].fm.lSubscriptYOffset;
  1165.             return True;
  1166.             break;
  1167.         case XA_UNDERLINE_POSITION:
  1168.             *value_return = (unsigned long)
  1169.                    logfonts[(LONG)font_struct->fid].fm.lUnderscorePosition;
  1170.             return True;
  1171.             break;
  1172.         case XA_UNDERLINE_THICKNESS:
  1173.             *value_return = (unsigned long)
  1174.                    logfonts[(LONG)font_struct->fid].fm.lUnderscoreSize;
  1175.             return True;
  1176.             break;
  1177.         case XA_STRIKEOUT_ASCENT:
  1178.             *value_return = (unsigned long)
  1179.                    logfonts[(LONG)font_struct->fid].fm.lStrikeoutPosition;
  1180.             return True;
  1181.             break;
  1182.         case XA_STRIKEOUT_DESCENT:
  1183.             *value_return = (unsigned long)
  1184.                    logfonts[(LONG)font_struct->fid].fm.lStrikeoutSize
  1185.                    - logfonts[(LONG)font_struct->fid].fm.lStrikeoutPosition;
  1186.             return True;
  1187.             break;
  1188.         case XA_ITALIC_ANGLE: /* scaled by 64 */
  1189.             /* Degrees in sCharSlope second byte, minutes first byte */
  1190. /* Endian-ness!!! */
  1191.             *value_return = (unsigned long) 64 * 90 -
  1192.                    (logfonts[(LONG)font_struct->fid].fm.sCharSlope >> 2);
  1193.             return True;
  1194.             break;
  1195.         case XA_X_HEIGHT:
  1196.             *value_return = (unsigned long)
  1197.                    logfonts[(LONG)font_struct->fid].fm.lXHeight;
  1198.             return True;
  1199.             break;
  1200.         case XA_QUAD_WIDTH:
  1201.             *value_return = (unsigned long)
  1202.                    logfonts[(LONG)font_struct->fid].fm.lEmInc;
  1203.             return True;
  1204.             break;
  1205.         case XA_CAP_HEIGHT:
  1206.             /* Same as max height */
  1207.             *value_return = (unsigned long)
  1208.                    logfonts[(LONG)font_struct->fid].fm.lMaxAscender;
  1209.             return True;
  1210.             break;
  1211.         case XA_WEIGHT:
  1212.             /* Scale of 0 to 1000 */
  1213.             *value_return = (unsigned long)
  1214.                    100 * logfonts[(LONG)font_struct->fid].fm.usWeightClass;
  1215.             return True;
  1216.             break;
  1217.         case XA_POINT_SIZE:
  1218.             *value_return = (unsigned long)
  1219.                    logfonts[(LONG)font_struct->fid].fm.sNominalPointSize;
  1220.             return True;
  1221.             break;
  1222.         case XA_RESOLUTION:
  1223.             /* expressed in hundredths */
  1224.             /* Fontmetrics give two fields: sXDeviceRes and sYDeviceRes */
  1225.             /* in pels/inch for bitmap fonts, notional units/Em for outline */
  1226.             if (logfonts[(LONG)font_struct->fid].fm.fsDefn & FM_DEFN_OUTLINE) {
  1227.                 /* Em size gives point size */
  1228.                 *value_return = (unsigned long)
  1229.                 logfonts[(LONG)font_struct->fid].fm.sXDeviceRes* fm.lEmInc* 100;
  1230.             } else {
  1231.                 /* multiply by number of points in one inch, 72, + 100ths */
  1232.                 *value_return = (unsigned long)
  1233.                        logfonts[(LONG)font_struct->fid].fm.sXDeviceRes * 722818;
  1234.             }
  1235.             return True;
  1236.             break;
  1237.         default:
  1238.             return False;
  1239.             break;
  1240.     }
  1241. }
  1242.  
  1243. /*
  1244.  *----------------------------------------------------------------------
  1245.  *
  1246.  * TkOS2ScaleFont --
  1247.  *
  1248.  *      Adapted from "OS/2 Presentation Manager Programming" by Petzold.
  1249.  *    Called to scale a presentation space's font to a desired size.
  1250.  *
  1251.  * Results:
  1252.  *    Return true if successful.
  1253.  *
  1254.  * Side effects:
  1255.  *    Sets the character box attribute of a presentation space.
  1256.  *
  1257.  *----------------------------------------------------------------------
  1258.  */
  1259.  
  1260. BOOL
  1261. TkOS2ScaleFont(hps, pointSize, pointWidth)
  1262.     HPS hps;
  1263.     ULONG pointSize;    /* in decipixels */
  1264.     ULONG pointWidth;    /* 0 means "same as pointSize" */
  1265. {
  1266.     HDC hdc;
  1267.     LONG xRes, yRes;
  1268.     POINTL points[2];
  1269.     SIZEF sizef;
  1270.  
  1271.     /* If pointWidth defaulted, set it to pointSize */
  1272.     if (pointWidth == 0) {
  1273.         pointWidth = pointSize;
  1274.     }
  1275.  
  1276.     /* Determine device and its resolutions */
  1277.     hdc = GpiQueryDevice(hps);
  1278.     if (hdc == HDC_ERROR) {
  1279.         return FALSE;
  1280.     } else if (hdc == NULLHANDLE) {
  1281.         /* No device context associated, assume the screen */
  1282.         xRes = aDevCaps[CAPS_HORIZONTAL_FONT_RES];
  1283.         yRes = aDevCaps[CAPS_VERTICAL_FONT_RES];
  1284.     } else {
  1285.         rc = DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 1, &xRes);
  1286.         if (rc != TRUE) {
  1287.             xRes = aDevCaps[CAPS_HORIZONTAL_FONT_RES];
  1288.         }
  1289.         rc = DevQueryCaps(hdc, CAPS_VERTICAL_FONT_RES, 1, &yRes);
  1290.         if (rc != TRUE) {
  1291.             yRes = aDevCaps[CAPS_VERTICAL_FONT_RES];
  1292.         }
  1293.     }
  1294.  
  1295.     FIX_RES(xRes);
  1296.     FIX_RES(yRes);
  1297.  
  1298.     /*
  1299.      * Determine desired point size in pixels with device resolution.
  1300.      * Font resolution is returned by PM in pels per inch, device resolution
  1301.      * is in dots per inch. 722.818 decipoints in an inch.
  1302.      * Add 361.409 for correct rounding.
  1303.      */
  1304.     points[0].x = 0;
  1305.     points[0].y = 0;
  1306.     points[1].x = (xRes * pointWidth + 361.409) / 722.818;
  1307.     points[1].y = (yRes * pointSize + 361.409) / 722.818;
  1308.  
  1309.     /* Convert to page coordinates */
  1310.     rc = GpiConvert(hps, CVTC_DEVICE, CVTC_PAGE, 2L, points);
  1311.  
  1312.     /* Now set the character box */
  1313.     sizef.cx = MAKEFIXED((points[1].x - points[0].x), 0);
  1314.     sizef.cy = MAKEFIXED((points[1].y - points[0].y), 0);
  1315.  
  1316.     return GpiSetCharBox(hps, &sizef);
  1317. }
  1318.