home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / spmio10.zip / gcc2 / stdwin / stdfont.cc < prev    next >
C/C++ Source or Header  |  1994-08-28  |  10KB  |  358 lines

  1. #include <stdio.h>
  2.  
  3. #ifdef NDEBUG
  4. #define LOG(format, args...)
  5. #else
  6. FILE *logfile;
  7. #define LOG(format, args...) \
  8. fprintf (logfile, "%s:%d: " format "\n", __FILE__, __LINE__ , ##args )
  9. #endif
  10.  
  11. #include <stdlib.h>
  12. #include <stdfont.h>
  13. #include <limits.h>
  14. #include <string.h>
  15.  
  16. #define countof(A) (sizeof (A) / sizeof ((A)[0]))
  17.      
  18. FontInformation::FontInformation (HWND hwnd)
  19. {
  20.   HPS hps = WinGetPS (hwnd);
  21.   HDC hdc = GpiQueryDevice (hps);
  22.  
  23.   // Get out the vertical and horizontal device resolution for later use
  24.   DevQueryCaps (hdc, CAPS_HORIZONTAL_FONT_RES, 1, &xres);
  25.   DevQueryCaps (hdc, CAPS_VERTICAL_FONT_RES, 1, &yres);
  26.  
  27.   // Query the number of fonts involved
  28.   long foobar = 0;
  29.   font_count = GpiQueryFonts (hps, QF_PUBLIC, 0, &foobar, 0, 0);
  30.  
  31.   // Allocate enough room to store all font information
  32.   font_metrics = (FONTMETRICS *) malloc (font_count * sizeof (*font_metrics));
  33.  
  34.   // Fill the newly allocated array with all the font information
  35.   foobar = font_count;
  36.   GpiQueryFonts (hps, QF_PUBLIC, 0, &foobar,
  37.          sizeof (*font_metrics), font_metrics);
  38.  
  39.   WinReleasePS (hps);
  40.  
  41.   int i;
  42.   for (i = 0; i < countof (default_font_set); i++)
  43.     default_font_set[i] = 0;
  44.  
  45. #ifndef NDEBUG  
  46.   for (i = 0; i < font_count; i++)
  47.     {
  48.       FONTMETRICS *fm = &font_metrics[i];
  49.       LOG ("Font #%d", i);
  50.       LOG ("    Family: `%s', Face: `%s'", fm->szFamilyname, fm->szFacename);
  51.       LOG ("    Point size: %d, xres: %d, yres: %d", fm->sNominalPointSize,
  52.        fm->sXDeviceRes, fm->sYDeviceRes);
  53.       LOG ("    Selection: 0x%X, Defn: 0x%X", fm->fsSelection, fm->fsDefn);
  54.     }
  55. #endif
  56. }
  57.  
  58. FontInformation::~FontInformation ()
  59. {
  60.   if (font_metrics)
  61.     free (font_metrics);
  62. }
  63.  
  64.  
  65. // The following condition functions are used to test a fontmetric
  66. // to see if it matches a desired condition     
  67. struct MatchInfo
  68. {
  69.   const char *facename;
  70.   int pointsize;
  71.   int xres, yres;
  72. };
  73.  
  74. typedef int (*MatchFunction) (const FONTMETRICS *, const MatchInfo *);
  75.  
  76. static int fm_match (int fontcount, const FONTMETRICS *fm, MatchInfo *mi,
  77.              MatchFunction matchfunction)
  78. {
  79.   int i;
  80.   for (i = 0; i < fontcount; i++)
  81.     {
  82.       const FONTMETRICS * const metric = &fm[i];
  83.       // Only match fonts with the right facename
  84.       if (strcmp (metric->szFacename, mi->facename))
  85.     continue;
  86.       // See if the match function thinks the font is ok
  87.       if (matchfunction (metric, mi))
  88.     return i;
  89.     }
  90.   return -1;
  91. }
  92.  
  93. static int fm_exact_bitmap_font (FONTMETRICS *fm, MatchInfo *mi)
  94. {
  95.   return
  96.     (!(fm->fsDefn & FM_DEFN_OUTLINE)        // Bitmap font
  97.      && fm->sNominalPointSize == mi->pointsize    // Right pointsize
  98.      && fm->sXDeviceRes == mi->xres        // Right X resolution
  99.      && fm->sYDeviceRes == mi->yres);        // Right Y resolution
  100. }
  101.  
  102. static int fm_exact_vector_font (const FONTMETRICS *fm, const MatchInfo *mi)
  103. {
  104.   return
  105.     ((fm->fsDefn & FM_DEFN_OUTLINE)            // Vector font
  106.      && fm->sNominalPointSize == mi->pointsize);    // Exact point size
  107. }
  108.  
  109. static int fm_inexact_vector_font (const FONTMETRICS *fm, const MatchInfo *mi)
  110. {
  111.   return
  112.     ((fm->fsDefn & FM_DEFN_OUTLINE)            // Vector font
  113.      && fm->sMinimumPointSize <= mi->pointsize        // Font ok sizewise
  114.      && mi->pointsize <= fm->sMaximumPointSize);
  115. }
  116.  
  117. static int fm_poor_vector_font (const FONTMETRICS *fm, const MatchInfo *mi)
  118. {
  119.   return (fm->fsDefn & FM_DEFN_OUTLINE); // Any vector font
  120. }
  121.  
  122. int FontInformation::find_match (const char *fontspec, unsigned *pointsize)
  123. {
  124.   // Make sure we have a valid argument
  125.   if (fontspec == 0)
  126.     return -1;
  127.  
  128.   // Parse the point size
  129.   char *rest;
  130.   unsigned long ptsize = strtoul (fontspec, &rest, 10);
  131.   if (*rest != '.' || ptsize == ULONG_MAX)
  132.     return -1;
  133.   rest++; // Skip the '.'
  134.   ptsize *= 10;
  135.   if (pointsize)
  136.     *pointsize = ptsize;
  137.  
  138.   // Skip italic and bold specifiers
  139.   const char * const boldspec = "bold.";
  140.   const char * const italicspec = "italic.";
  141.   const int boldspeclen = strlen (boldspec);
  142.   const int italicspeclen = strlen (italicspec);
  143.   do {
  144.     if (!strncmp (rest, boldspec, boldspeclen))
  145.       {
  146.     rest += boldspeclen;
  147.     continue;
  148.       }
  149.     if (!strncmp (rest, italicspec, italicspeclen))
  150.       {
  151.     rest += italicspeclen;
  152.     continue;
  153.       }
  154.   } while (0);
  155.  
  156.   // The rest of the stuff is the face name
  157.   const char * const face_name = rest;
  158.   if (face_name[0] == '\0')
  159.     return -1;
  160.  
  161.   // Then find a match
  162.   MatchInfo matchinfo;
  163.   matchinfo.facename = face_name;
  164.   matchinfo.pointsize = ptsize;
  165.   matchinfo.xres = xres;
  166.   matchinfo.yres = yres;
  167.   MatchFunction matchfunctions[] = {
  168.     fm_exact_bitmap_font,
  169.     fm_exact_vector_font,
  170.     fm_inexact_vector_font,
  171.     fm_poor_vector_font
  172.     };
  173.   int i;
  174.   for (i = 0; i < countof (matchfunctions); i++)
  175.     {
  176.       int match = fm_match (font_count, font_metrics, &matchinfo,
  177.                 matchfunctions[i]);
  178.       if (match != -1)
  179.     return match;
  180.     }
  181.   return -1;
  182. }
  183.  
  184. int FontInformation::install_font (const char *fontspec)
  185. {
  186.   unsigned pointsize;
  187.   int fontindex = find_match (fontspec, &pointsize);
  188.   LOG ("Match for `%s' found at index %d", fontspec, fontindex);
  189.   if (fontindex < 0 || font_count <= fontindex)
  190.     return 0;
  191.   int i;
  192.   for (i = 1; i < countof (default_font_set); i++)
  193.     if (default_font_set[i] == 0)
  194.       {
  195.     LOG ("Installing index %d in font slot %d", fontindex, i);
  196.     default_font_set[i] = &font_metrics[fontindex];
  197.     LOG ("FOOBAR #1 is at %p", default_font_set[1]);
  198.     default_font_pointsize[i] = pointsize;
  199.     return i;
  200.       }
  201.   return 0;
  202. }
  203.  
  204. void FontInformation::deinstall_font (int fonthandle)
  205. {
  206.   if (fonthandle < 0 || countof (default_font_set) <= fonthandle)
  207.     return;
  208.   default_font_set[fonthandle] = 0;
  209. }
  210.  
  211. void FontInformation::make_fonts_availible (HPS hps)
  212. {
  213.   int i;
  214.   for (i = 1; i < 256; i++)
  215.     {
  216.       const FONTMETRICS * const fm = default_font_set[i];
  217.       if (fm != 0)
  218.     {
  219.       // Convert the fontmetric into a fattrs
  220.       FATTRS fa;
  221.       memset (&fa, 0, sizeof (fa));
  222.       fa.usRecordLength = sizeof (fa);
  223.       fa.lMatch = fm->lMatch;
  224.       strcpy (fa.szFacename, fm->szFacename);
  225.       fa.idRegistry = fm->idRegistry;
  226.       if ((fm->fsDefn & FM_DEFN_OUTLINE))
  227.         fa.fsType = FATTR_TYPE_KERNING;
  228.       else
  229.         {
  230.           fa.lMaxBaselineExt = fm->lMaxBaselineExt;
  231.           fa.lAveCharWidth = fm->lAveCharWidth;
  232.         }
  233.       // Then create a suitable logical font
  234.       GpiCreateLogFont (hps, 0, i, &fa);
  235.     }
  236.     }
  237. }
  238.  
  239. void FontInformation::use_font (HPS hps, int fonthandle)
  240. {
  241.   if (default_font_set[fonthandle] == 0)
  242.     {
  243.       GpiSetCharSet (hps, 0);
  244.       return;
  245.     }
  246.   GpiSetCharSet (hps, fonthandle);
  247.   // If using a vector font, set up the point size
  248.   if ((default_font_set[fonthandle]->fsDefn & FM_DEFN_OUTLINE))
  249.     {
  250.       SIZEF box;
  251.       box.cx = ((xres * default_font_pointsize[fonthandle]) << 16) / 720;
  252.       box.cy = ((yres * default_font_pointsize[fonthandle]) << 16) / 720;
  253.       GpiSetCharBox (hps, &box);
  254.     }
  255. }
  256.  
  257. const FONTMETRICS *FontInformation::get_fontmetrics (int fonthandle)
  258. {
  259.   return default_font_set[fonthandle];
  260. }
  261.  
  262. int FontInformation::get_font_height (int fonthandle)
  263. {
  264.   const FONTMETRICS *fm = default_font_set[fonthandle];
  265.   if (fm == 0)
  266.     return 0;
  267.   if (fm->fsDefn & FM_DEFN_OUTLINE)
  268.     // Scale the vector font appropriately
  269.     return (yres * default_font_pointsize[fonthandle]) / 720;
  270.   else
  271.     return fm->lMaxBaselineExt;
  272. }
  273.  
  274. int FontInformation::get_fonts_height ()
  275. {
  276.   int height = 0;
  277.   for (int i = 0; i < countof (default_font_set); i++)
  278.     {
  279.       int fontheight = get_font_height (i);
  280.       if (fontheight > height)
  281.     height = fontheight;
  282.     }
  283.   return height;
  284. }
  285.  
  286. int FontInformation::get_font_width (int fonthandle)
  287. {
  288.   const FONTMETRICS *fm = default_font_set[fonthandle];
  289.   if (fm == 0)
  290.     return 0;
  291.   if (fm->fsDefn & FM_DEFN_OUTLINE)
  292.     {
  293.       const unsigned fx_lMaxBaselineExt =
  294.     ((xres * default_font_pointsize[fonthandle]) << 16) / 720;
  295.       const unsigned fx_lAveCharWidth =
  296.     (fx_lMaxBaselineExt * fm->lAveCharWidth) / fm->lMaxBaselineExt;
  297.       return fx_lAveCharWidth >> 16;
  298.     }
  299.   else
  300.     return fm->lAveCharWidth;
  301. }
  302.  
  303. int FontInformation::get_fonts_width ()
  304. {
  305.   int width = 0;
  306.   for (int i = 0; i < countof (default_font_set); i++)
  307.     {
  308.       int fontwidth = get_font_width (i);
  309.       if (fontwidth > width)
  310.     width = fontwidth;
  311.     }
  312.   return width;
  313. }
  314.  
  315. int FontInformation::get_font_descender (int fonthandle)
  316. {
  317.   const FONTMETRICS *fm = default_font_set[fonthandle];
  318.   if (fm == 0)
  319.     return 0;
  320.   if (fm->fsDefn & FM_DEFN_OUTLINE)
  321.     {
  322.       const unsigned fx_lMaxBaselineExt =
  323.     ((yres * default_font_pointsize[fonthandle]) << 16) / 720;
  324.       const unsigned fx_lMaxDescender =
  325.     (fx_lMaxBaselineExt * fm->lMaxDescender) / fm->lMaxBaselineExt;
  326.       return fx_lMaxDescender >> 16;
  327.     }
  328.   else
  329.     return fm->lMaxDescender;
  330. }
  331.  
  332. int FontInformation::get_fonts_descender ()
  333. {
  334.   int descender = 0;
  335.   for (int i = 1; i < countof (default_font_set); i++)
  336.     {
  337.       int fontdescender = get_font_descender (i);
  338.       if (fontdescender > descender)
  339.     descender = fontdescender;
  340.     }
  341.   return descender;
  342. }
  343.  
  344. int FontInformation::string_width (HPS hps, int length, const char *text)
  345. {
  346.   POINTL pts[TXTBOX_COUNT];
  347.   GpiQueryTextBox (hps, length, text, TXTBOX_COUNT, pts);
  348.   return pts[TXTBOX_TOPRIGHT].x;
  349. }
  350.  
  351.  
  352. FontInformation *desktop_fontinfo = 0;
  353.  
  354. void init_desktop_fontinfo ()
  355. {
  356.   desktop_fontinfo = new FontInformation (HWND_DESKTOP);
  357. }
  358.