diff src/objects-msw.c @ 872:79c6ff3eef26

[xemacs-hg @ 2002-06-20 21:18:01 by ben] font changes etc.; some 21.4 changes mule/mule-msw-init-late.el: Specify charset->windows-registry conversion. mule/mule-x-init.el: Delete extra mule font additions here. Put them in faces.c. cl-macs.el: Document better. font-lock.el: Move Lisp function regexp to lisp-mode.el. lisp-mode.el: Various indentation fixes: Handle flet functions better. Handle argument lists in defuns and flets. Handle quoted lists, e.g. property lists -- don't indent like function calls. Distinguish between lambdas and other lists. lisp-mode.el: Handle this form. faces.el, font-menu.el, font.el, gtk-faces.el, msw-faces.el, msw-font-menu.el, x-faces.el, x-init.el: Major overhaul of face-handling code: -- Fix lots of bogus code in msw-faces.el, msw-font-menu.el, font-menu.el that was "truenaming" font specs -- i.e. in the process of frobbing a particular field in a general user-specified font spec with wildcarded fields, sticking in particular values for all the remaining wildcarded fields. This bug was rampant everywhere except in x-faces.el (the oldest and only correctly written code). This also means that we need to work with font names at all times and not font instances, because a font instance is essentially a truenamed font. -- Total rewrite of extremely junky code in msw-faces.el. Work with names as well as font instances, and return names; stop truenaming when canonicalizing and frobbing; fix handling of the combined style field, i.e. weight/slant (also fixed in font.el). -- Totally rewrite the frobbing functions in faces.el. This time, we frob all the instantiators rather than just computing a single instance value and working backwards. That way, e.g., `bold' will work for all charsets that have bold available, rather than only for whatever charset was part of the computed font instance (another example of the truename virus). Also fix up code to look at the fallbacks (all of them) when no global value present, so we don't need to put something in the global value. Intelligently handle a request to frob a buffer locale, rather than signalling an error. When frobbing instantiators, try hard to figure out what device type is associated with them, and frob each according to its own proper device type. Correctly handle inheritance vectors given as instantiators. Preserve existing tags when putting back frobbed instantiators. Extract out general specifier-frobbing code into specifier.el. Document everything cleanly. Do lots of other things better, etc. -- Don't duplicatively set a global specification for the default font -- it's already in the fallback and we no longer need a default global specification present. Delete various code in x-faces.el and msw-faces.el that duplicated the lists of fonts in faces.c. -- init-global-faces was not being called at all under MS Windows! Major bogosity. That caused device-specific values to get stuck into all the fonts, making it very hard to change them -- setting global specs caused nothing to happen. -- Correct weight names in font.el. -- Lots more font fixups in objects*.c. Printer.el: Warning fix. specifier.el: Add more args to map-specifier. Add various "heuristic" specifier functions to aid in creation of specifier-munging code such as in faces.el. subr.el: New functions. lwlib.c: Fix warning. config.inc.samp: Clean up, add args to control fastcall (not yet supported! the changes needed are in another ws of mine), profile support, vc6 support, union-type. xemacs.dsp, xemacs.mak: Semi-major overhaul. Fix bug where dump-id was always getting recomputed, forcing a redump even when nothing changed. Add support for fastcall. Support edit-and-continue (on by default) with vc6. Use incremental linking when doing a debug compilation. Add support for profiling. Consolidate the various debug flags. Partial support for "batch-compiling" -- compiling many files on a single invocation of the compiler. Doesn't seem to help that much for me, so it's not finished or enabled by default. Remove HAVE_MSW_C_DIRED, we always do. Correct some sloppy use of directories. s/cygwin32.h: Allow pdump to work under Cygwin (mmap is broken, so need to undefine HAVE_MMAP). s/win32-common.h, s/windowsnt.h: Support for fastcall. Add WIN32_ANY for identifying all Win32 variants (Cygwin, native, MinGW). Both of these are properly used in another ws. alloc.c, balloon-x.c, buffer.c, bytecode.c, callint.c, cm.c, cmdloop.c, cmds.c, console-gtk.c, console-gtk.h, console-msw.c, console-msw.h, console-stream.c, console-stream.h, console-tty.c, console-tty.h, console-x.c, console-x.h, console.c, console.h, device-gtk.c, device-msw.c, device-tty.c, device-x.c, device.c, device.h, devslots.h, dialog-gtk.c, dialog-msw.c, dialog-x.c, dialog.c, dired-msw.c, editfns.c, emacs.c, event-Xt.c, event-gtk.c, event-msw.c, event-stream.c, event-tty.c, event-unixoid.c, events.c, extents.c, extents.h, faces.c, fileio.c, fns.c, frame-gtk.c, frame-msw.c, frame-tty.c, frame-x.c, frame.c, frame.h, glyphs-eimage.c, glyphs-gtk.c, glyphs-msw.c, glyphs-widget.c, glyphs-x.c, glyphs.c, glyphs.h, gui-gtk.c, gui-msw.c, gui-x.c, gui.c, gutter.c, input-method-xlib.c, intl-encap-win32.c, intl-win32.c, keymap.c, lisp.h, macros.c, menubar-gtk.c, menubar-msw.c, menubar-x.c, menubar.c, menubar.h, minibuf.c, mule-charset.c, nt.c, objects-gtk.c, objects-gtk.h, objects-msw.c, objects-msw.h, objects-tty.c, objects-tty.h, objects-x.c, objects-x.h, objects.c, objects.h, postgresql.c, print.c, process.h, redisplay-gtk.c, redisplay-msw.c, redisplay-output.c, redisplay-tty.c, redisplay-x.c, redisplay.c, redisplay.h, scrollbar-gtk.c, scrollbar-msw.c, scrollbar-x.c, scrollbar.c, select-gtk.c, select-msw.c, select-x.c, select.c, signal.c, sound.c, specifier.c, symbols.c, syntax.c, sysdep.c, syssignal.h, syswindows.h, toolbar-common.c, toolbar-gtk.c, toolbar-msw.c, toolbar-x.c, toolbar.c, unicode.c, window.c, window.h: The following are the major changes made: (1) Separation of various header files into an external and an internal version, similar to the existing separation of process.h and procimpl.h. Eventually this should be done for all Lisp objects. The external version has the same name as currently; the internal adds -impl. The external file has XFOO() macros for objects, but the structure is opaque and defined only in the internal file. It's now reasonable to move all prototypes in lisp.h into the appropriate external file, and this should be done. Currently, separation has been done on extents.h, objects*.h, console.h, device.h, frame.h, and window.h. For c/d/f/w, the most basic properties are available in the external header file, with the macros resolving to functions. In the internal header file, the macros are redefined to directly access the structure. Also, the global MARK_FOO_CHANGED macros have been made into functions so that they can be accessed without needing to include lots of -impl headers -- they are used in almost exclusively in non-time-critical functions, and take up enough time that the function overhead will be negligible. Similarly, the function overhead from making the basic properties mentioned above into functions is negligible, and code that does heavy accessing of c/d/f/w structures inevitably ends up needing the internal header files, anyway. (2) More face changes. -- Major rewrite of objects-msw.c. Now handles wildcard specs properly, rather than "truenaming" (or even worse, signalling an error, which previously happened with some of the fallbacks if you tried to use them in make-font-instance!). -- Split charset matching of fonts into two stages -- one to find a font specifically designed for a particular charset (by examining its registry), the second to find a Unicode font that can support the charset. This needs to proceed as two complete, separate instantiations in order to work properly (otherwise many of the fonts in the HELLO page look wrong). This should also make it easy to support iso10646 (Unicode) fonts under X. -- All default values for fonts are now completely specified in the fallbacks. Stuff from mule-x-init.el has all been moved here, merged with the existing specs, and totally rethought so you get sensible results. (HELLO now looks much better!). -- Generalize the "default X/GTK device" stuff into a per-device-type "default device". -- Add mswindows-{set-}charset-registry. In time, charset<->code-page conversion functions will be removed. -- Wrap protective code around calls to compute device specifier tags, and do this computation before calling the face initialization code because the latter may need these tags to be correctly updated. (3) Other changes. EmacsFrame.c, glyphs-msw.c, eval.c, gui-x.c, intl-encap-win32.c, search.c, signal.c, toolbar-msw.c, unicode.c: Warning fixes. config.h.in: #undefs meant to be frobbed by configure *MUST* go inside of #ifndef WIN32_NO_CONFIGURE, and everything else *MUST* go outside! eval.c: Let detailed backtraces be detailed. specifier.c: Don't override user's print-string-length/print-length settings. glyphs.c: New function image-instance-instantiator. config.h.in, sysdep.c: Changes for fastcall. sysdep.c, nt.c: Fix up a previous botched patch that tried to add support for both EEXIST and EACCES. IF THE BOTCHED PATCH WENT INTO 21.4, THIS FIXUP NEEDS TO GO IN, TOO. search.c: Fix *evil* crash due to incorrect synching of syntax-cache code with 21.1. THIS SHOULD GO INTO 21.4.
author ben
date Thu, 20 Jun 2002 21:19:10 +0000
parents 804517e16990
children a1e328407366
line wrap: on
line diff
--- a/src/objects-msw.c	Tue Jun 11 19:28:22 2002 +0000
+++ b/src/objects-msw.c	Thu Jun 20 21:19:10 2002 +0000
@@ -38,12 +38,12 @@
 #include <config.h>
 #include "lisp.h"
 
-#include "console-msw.h"
-#include "objects-msw.h"
+#include "console-msw-impl.h"
+#include "objects-msw-impl.h"
 
 #include "buffer.h"
 #include "charset.h"
-#include "device.h"
+#include "device-impl.h"
 #include "elhash.h"
 #include "insdel.h"
 #include "opaque.h"
@@ -751,8 +751,8 @@
   {"Black"		, FW_BLACK}
 };
 
-/* Default charset first, no synonyms allowed because these names are
- * matched against the names reported by win32 by match_font() */
+/* Default charset must be listed first, no synonyms allowed because these
+ * names are matched against the names reported by win32 by match_font() */
 static const fontmap_t charset_map[] =
 {
   {"Western"		, ANSI_CHARSET}, /* Latin 1 */
@@ -1142,8 +1142,14 @@
 
   /* Add the font name to the list if not already there */
   fontname_lispstr = build_intstring (fontname);
-  if (NILP (Fmember (fontname_lispstr, font_enum->list)))
-    font_enum->list = Fcons (fontname_lispstr, font_enum->list);
+  if (NILP (Fassoc (fontname_lispstr, font_enum->list)))
+    font_enum->list =
+      Fcons (Fcons (fontname_lispstr,
+		    /* TMPF_FIXED_PITCH is backwards from what you expect!
+		       If set, it means NOT fixed pitch. */
+		    (lpntme->ntmTm.tmPitchAndFamily & TMPF_FIXED_PITCH) ?
+		    Qnil : Qt),
+	     font_enum->list);
 
   return 1;
 }
@@ -1159,6 +1165,94 @@
 				(LPARAM) font_enum, 0);
 }
 
+/* Function for sorting lists of fonts as obtained from
+   mswindows_enumerate_fonts().  These come in a known format:
+   "family::::charset" for TrueType fonts, "family::size::charset"
+   otherwise. */
+
+static int
+sort_font_list_function (Lisp_Object obj1, Lisp_Object obj2,
+			 Lisp_Object pred)
+{
+  Ibyte *font1, *font2;
+  Ibyte *c1, *c2;
+  int t1, t2;
+
+  /*
+    1. fixed over proportional.
+    2. Western over other charsets.
+    3. TrueType over non-TrueType.
+    4. Within non-TrueType, sizes closer to 10pt over sizes farther from 10pt.
+    5. Courier New over other families.
+  */
+
+  /* The sort function should return > 0 if OBJ1 < OBJ2, < 0 otherwise.
+     NOTE: This is backwards from the way qsort() works. */
+
+  t1 = !NILP (XCDR (obj1));
+  t2 = !NILP (XCDR (obj2));
+
+  if (t1 && !t2)
+    return 1;
+  if (t2 && !t1)
+    return -1;
+
+  font1 = XSTRING_DATA (XCAR (obj1));
+  font2 = XSTRING_DATA (XCAR (obj2));
+
+  c1 = qxestrrchr (font1, ':');
+  c2 = qxestrrchr (font2, ':');
+
+  t1 = !qxestrcasecmp_c (c1 + 1, "western");
+  t2 = !qxestrcasecmp_c (c2 + 1, "western");
+
+  if (t1 && !t2)
+    return 1;
+  if (t2 && !t1)
+    return -1;
+
+  c1 -= 2;
+  c2 -= 2;
+  t1 = *c1 == ':';
+  t2 = *c2 == ':';
+
+  if (t1 && !t2)
+    return 1;
+  if (t2 && !t1)
+    return -1;
+
+  if (!t1 && !t2)
+    {
+      while (isdigit (*c1))
+	c1--;
+      while (isdigit (*c2))
+	c2--;
+
+      t1 = qxeatoi (c1 + 1) - 10;
+      t2 = qxeatoi (c2 + 1) - 10;
+
+      if (abs (t1) < abs (t2))
+	return 1;
+      else if (abs (t2) < abs (t1))
+	return -1;
+      else if (t1 < t2)
+	/* Prefer a smaller font over a larger one just as far away
+	   because the smaller one won't upset the total line height if it's
+	   just a few chars. */
+	return 1;
+    }
+
+  t1 = !qxestrncasecmp_c (font1, "courier new:", 12);
+  t2 = !qxestrncasecmp_c (font2, "courier new:", 12);
+
+  if (t1 && !t2)
+    return 1;
+  if (t2 && !t1)
+    return -1;
+
+  return -1;
+}
+
 /*
  * Enumerate the available on the HDC fonts and return a list of string
  * font names.
@@ -1182,7 +1276,7 @@
   qxeEnumFontFamiliesEx (hdc, &logfont, (FONTENUMPROCW) font_enum_callback_1,
 			 (LPARAM) (&font_enum), 0);
 
-  return font_enum.list;
+  return list_sort (font_enum.list, Qnil, sort_font_list_function);
 }
 
 static HFONT
@@ -1320,20 +1414,36 @@
 static void
 mswindows_finalize_font_instance (Lisp_Font_Instance *f);
 
-static HFONT
-create_hfont_from_font_spec (const Ibyte *namestr,
-			     HDC hdc,
-			     Lisp_Object name_for_errors,
-			     Lisp_Object device_font_list,
-			     Error_Behavior errb)
+/* Parse the font spec in NAMESTR.  Maybe issue errors, according to ERRB;
+   NAME_FOR_ERRORS is the Lisp string to use when issuing errors.  Store
+   the five parts of the font spec into the given strings, which should be
+   declared as
+
+   Ibyte fontname[LF_FACESIZE], weight[LF_FACESIZE], points[8];
+   Ibyte effects[LF_FACESIZE], charset[LF_FACESIZE];
+
+   If LOGFONT is given, store the necessary information in LOGFONT to
+   create a font object.  If LOGFONT is given, HDC must also be given;
+   else, NULL can be given for both.
+   
+   Return 1 if ok, 0 if error.
+   */
+static int
+parse_font_spec (const Ibyte *namestr,
+		 HDC hdc,
+		 Lisp_Object name_for_errors,
+		 Error_Behavior errb,
+		 LOGFONTW *logfont,
+		 Ibyte *fontname,
+		 Ibyte *weight,
+		 Ibyte *points,
+		 Ibyte *effects,
+		 Ibyte *charset)
 {
-  LOGFONTW logfont;
   int fields, i;
   int pt;
-  Ibyte fontname[LF_FACESIZE], weight[LF_FACESIZE], *style, points[8];
-  Ibyte effects[LF_FACESIZE], charset[LF_FACESIZE];
+  Ibyte *style;
   Ibyte *c;
-  HFONT hfont;
 
   /*
    * mswindows fonts look like:
@@ -1348,6 +1458,15 @@
    *	Courier New:Bold Italic:10:underline strikeout:western
    */
 
+  fontname[0] = 0;
+  weight[0] = 0;
+  points[0] = 0;
+  effects[0] = 0;
+  charset[0] = 0;
+
+  if (logfont)
+    xzero (*logfont);
+
   fields = sscanf ((CIbyte *) namestr, "%31[^:]:%31[^:]:%7[^:]:%31[^:]:%31s",
 		   fontname, weight, points, effects, charset);
 
@@ -1361,7 +1480,7 @@
     {
       maybe_signal_error (Qinvalid_argument, "Invalid font", name_for_errors,
 			  Qfont, errb);
-      return NULL;
+      return 0;
     }
 
   if (fields > 0 && qxestrlen (fontname))
@@ -1369,14 +1488,12 @@
       Extbyte *extfontname;
 
       C_STRING_TO_TSTR (fontname, extfontname);
-      xetcsncpy ((Extbyte *) logfont.lfFaceName, extfontname, LF_FACESIZE - 1);
-      logfont.lfFaceName[LF_FACESIZE - 1] = 0;
-    }
-  else
-    {
-      maybe_signal_error (Qinvalid_argument, "Must specify a font name",
-			  name_for_errors, Qfont, errb);
-      return NULL;
+      if (logfont)
+	{
+          xetcsncpy ((Extbyte *) logfont->lfFaceName, extfontname,
+	             LF_FACESIZE - 1);
+	  logfont->lfFaceName[LF_FACESIZE - 1] = 0;
+	}
     }
 
   /* weight */
@@ -1385,31 +1502,33 @@
 
   /* Maybe split weight into weight and style */
   if ((c = qxestrchr (weight, ' ')))
-  {
-    *c = '\0';
-    style = c + 1;
-  }
+    {
+      *c = '\0';
+      style = c + 1;
+    }
   else
     style = NULL;
 
   for (i = 0; i < countof (fontweight_map); i++)
     if (!qxestrcasecmp_c (weight, fontweight_map[i].name))
       {
-	logfont.lfWeight = fontweight_map[i].value;
+	if (logfont)
+	  logfont->lfWeight = fontweight_map[i].value;
 	break;
       }
   if (i == countof (fontweight_map))	/* No matching weight */
     {
       if (!style)
 	{
-	  logfont.lfWeight = FW_REGULAR;
+	  if (logfont)
+	    logfont->lfWeight = FW_REGULAR;
 	  style = weight;	/* May have specified style without weight */
 	}
       else
 	{
 	  maybe_signal_error (Qinvalid_constant, "Invalid font weight",
 			      name_for_errors, Qfont, errb);
-	  return NULL;
+	  return 0;
 	}
     }
 
@@ -1417,41 +1536,59 @@
     {
       /* #### what about oblique? */
       if (qxestrcasecmp_c (style, "italic") == 0)
-	logfont.lfItalic = TRUE;
+	{
+	  if (logfont)
+	    logfont->lfItalic = TRUE;
+	}
       else
 	{
 	  maybe_signal_error (Qinvalid_constant,
 			      "Invalid font weight or style",
 			      name_for_errors, Qfont, errb);
-	  return NULL;
+	  return 0;
       }
 
       /* Glue weight and style together again */
       if (weight != style)
         *c = ' ';
     }
-  else
-    logfont.lfItalic = FALSE;
+  else if (logfont)
+    logfont->lfItalic = FALSE;
 
-  if (fields < 3)
-    pt = 10;	/* #### Should we reject strings that don't specify a size? */
-  else if ((pt = qxeatoi (points)) == 0)
+  if (fields < 3 || !qxestrcmp_c (points, ""))
+    ;
+  else if (points[0] == '0' ||
+	   qxestrspn (points, "0123456789") < qxestrlen (points))
     {
       maybe_signal_error (Qinvalid_argument, "Invalid font pointsize",
 			  name_for_errors, Qfont, errb);
-      return NULL;
+      return 0;
+    }
+  else
+    {
+      pt = qxeatoi (points);
+
+      if (logfont)
+	{
+	  /* Formula for pointsize->height from LOGFONT docs in MSVC5 Platform
+	     SDK */
+	  logfont->lfHeight = -MulDiv (pt, GetDeviceCaps (hdc, LOGPIXELSY),
+				       72);
+	  logfont->lfWidth = 0;
+	}
     }
 
-  /* Formula for pointsize->height from LOGFONT docs in MSVC5 Platform SDK */
-  logfont.lfHeight = -MulDiv (pt, GetDeviceCaps (hdc, LOGPIXELSY), 72);
-  logfont.lfWidth = 0;
+  /* Effects */
+  if (logfont)
+    {
+      logfont->lfUnderline = FALSE;
+      logfont->lfStrikeOut = FALSE;
+    }
 
-  /* Effects */
-  logfont.lfUnderline = FALSE;
-  logfont.lfStrikeOut = FALSE;
   if (fields >= 4 && effects[0] != '\0')
     {
       Ibyte *effects2;
+      int underline = FALSE, strikeout = FALSE;
 
       /* Maybe split effects into effects and effects2 */
       if ((c = qxestrchr (effects, ' ')))
@@ -1463,43 +1600,47 @@
         effects2 = NULL;
 
       if (qxestrcasecmp_c (effects, "underline") == 0)
-	logfont.lfUnderline = TRUE;
+	underline = TRUE;
       else if (qxestrcasecmp_c (effects, "strikeout") == 0)
-	logfont.lfStrikeOut = TRUE;
+	strikeout = TRUE;
       else
         {
           maybe_signal_error (Qinvalid_constant, "Invalid font effect",
 			      name_for_errors, Qfont, errb);
-	  return NULL;
+	  return 0;
 	}
 
       if (effects2 && effects2[0] != '\0')
 	{
 	  if (qxestrcasecmp_c (effects2, "underline") == 0)
-	    logfont.lfUnderline = TRUE;
+	    underline = TRUE;
 	  else if (qxestrcasecmp_c (effects2, "strikeout") == 0)
-	    logfont.lfStrikeOut = TRUE;
+	    strikeout = TRUE;
 	  else
 	    {
 	      maybe_signal_error (Qinvalid_constant, "Invalid font effect",
 				  name_for_errors, Qfont, errb);
-	      return NULL;
+	      return 0;
 	    }
         }
 
-      /* Regenerate sanitised effects string */
-      if (logfont.lfUnderline)
+      /* Regenerate sanitized effects string */
+      if (underline)
 	{
-	  if (logfont.lfStrikeOut)
+	  if (strikeout)
 	    qxestrcpy_c (effects, "underline strikeout");
 	  else
 	    qxestrcpy_c (effects, "underline");
 	}
-      else if (logfont.lfStrikeOut)
+      else if (strikeout)
 	qxestrcpy_c (effects, "strikeout");
+
+      if (logfont)
+	{
+	  logfont->lfUnderline = underline;
+	  logfont->lfStrikeOut = strikeout;
+	}
     }
-  else
-    effects[0] = '\0';
 
   /* Charset */
   /* charset can be specified even if earlier fields haven't been */
@@ -1511,76 +1652,173 @@
 	  qxestrncpy (charset, c + 1, LF_FACESIZE);
 	  charset[LF_FACESIZE - 1] = '\0';
 	}
-      else
-	qxestrcpy_c (charset, charset_map[0].name);
     }
 
-  for (i = 0; i < countof (charset_map); i++)
-    if (!qxestrcasecmp_c (charset, charset_map[i].name))
-      {
-	logfont.lfCharSet = charset_map[i].value;
-	break;
-      }
+  /* NOTE: If you give a blank charset spec, we will normally not get here
+     under Mule unless we explicitly call `make-font-instance'!  This is
+     because the C code instantiates fonts using particular charsets, by
+     way of specifier_matching_instance().  Before instantiating the font,
+     font_instantiate() calls the devmeth find_matching_font(), which gets
+     a truename font spec with the registry (i.e. the charset spec) filled
+     in appropriately to the charset. */
+  if (!qxestrcmp_c (charset, ""))
+    ;
+  else
+    {
+      for (i = 0; i < countof (charset_map); i++)
+	if (!qxestrcasecmp_c (charset, charset_map[i].name))
+	  {
+	    if (logfont)
+	      logfont->lfCharSet = charset_map[i].value;
+	    break;
+	  }
 
-  if (i == countof (charset_map))	/* No matching charset */
+      if (i == countof (charset_map))	/* No matching charset */
+	{
+	  maybe_signal_error (Qinvalid_argument, "Invalid charset",
+			      name_for_errors, Qfont, errb);
+	  return 0;
+	}
+    }
+
+  if (logfont)
     {
-      maybe_signal_error (Qinvalid_argument, "Invalid charset",
-			  name_for_errors, Qfont, errb);
-      return NULL;
+      /* Misc crud */
+#if 1
+      logfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
+      logfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+      logfont->lfQuality = DEFAULT_QUALITY;
+#else
+      logfont->lfOutPrecision = OUT_STROKE_PRECIS;
+      logfont->lfClipPrecision = CLIP_STROKE_PRECIS;
+      logfont->lfQuality = PROOF_QUALITY;
+#endif
+      /* Default to monospaced if the specified fontname doesn't exist. */
+      logfont->lfPitchAndFamily = FF_MODERN;
     }
 
-  /* Misc crud */
-  logfont.lfEscapement = logfont.lfOrientation = 0;
-#if 1
-  logfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
-  logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
-  logfont.lfQuality = DEFAULT_QUALITY;
-#else
-  logfont.lfOutPrecision = OUT_STROKE_PRECIS;
-  logfont.lfClipPrecision = CLIP_STROKE_PRECIS;
-  logfont.lfQuality = PROOF_QUALITY;
-#endif
-  /* Default to monospaced if the specified fontname doesn't exist. */
-  logfont.lfPitchAndFamily = FF_MODERN;
+  return 1;
+}
+
+/*
+  mswindows fonts look like:
+  	[fontname[:style[:pointsize[:effects]]]][:charset]
+   A maximal mswindows font spec looks like:
+  	Courier New:Bold Italic:10:underline strikeout:Western
+
+  A missing weight/style field is the same as Regular, and a missing
+  effects field is left alone, and means no effects; but a missing
+  fontname, pointsize or charset field means any will do.  We prefer
+  Courier New, 10, Western.  See sort function above. */
 
-  /* Windows will silently substitute a default font if the fontname specifies
-     a non-existent font. This is bad for screen fonts because it doesn't
-     allow higher-level code to see the error and to act appropriately.
-     For instance complex_vars_of_faces() sets up a fallback list of fonts
-     for the default face. */
+static HFONT
+create_hfont_from_font_spec (const Ibyte *namestr,
+			     HDC hdc,
+			     Lisp_Object name_for_errors,
+			     Lisp_Object device_font_list,
+			     Error_Behavior errb,
+			     Lisp_Object *truename_ret)
+{
+  LOGFONTW logfont;
+  HFONT hfont;
+  Ibyte fontname[LF_FACESIZE], weight[LF_FACESIZE], points[8];
+  Ibyte effects[LF_FACESIZE], charset[LF_FACESIZE];
+  Ibyte truename[MSW_FONTSIZE];
+  Ibyte truername[MSW_FONTSIZE];
+
+  /* Windows will silently substitute a default font if the fontname
+     specifies a non-existent font.  This is bad for screen fonts because
+     it doesn't allow higher-level code to see the error and to act
+     appropriately.  For instance complex_vars_of_faces() sets up a
+     fallback list of fonts for the default face.  Instead, we look at all
+     the possibilities and pick one that works, handling missing pointsize
+     and charset fields appropriately.
+
+     For printer fonts, we used to go ahead and let Windows choose the
+     font, and for those devices, then, DEVICE_FONT_LIST would be nil.
+     However, this causes problems with the font-matching code below, which
+     needs a list of fonts so it can pick the right one for Mule.
+
+     Thus, the code below to handle a nil DEVICE_FONT_LIST is not currently
+     used. */
 
   if (!NILP (device_font_list))
     {
-      Lisp_Object fonttail;
-      Ibyte truename[MSW_FONTSIZE];
+      Lisp_Object fonttail = Qnil;
+
+      if (!parse_font_spec (namestr, 0, name_for_errors,
+			    errb, 0, fontname, weight, points,
+			    effects, charset))
+	return 0;
+
+      /* The fonts in the device font list always specify fontname and
+	 charset, but often times not the size; so if we don't have the
+	 size specified either, do a round with size 10 so we'll always end
+	 up with a size in the truename (if we fail this one but succeed
+	 the next one, we'll have chosen a non-TrueType font, and in those
+	 cases the size is specified in the font list item. */
+
+      if (!points[0])
+	{
+	  qxesprintf (truename, "%s:%s:10:%s:%s",
+		      fontname, weight, effects, charset);
 
-      qxesprintf (truename, "%s:%s:%d:%s:%s", fontname, weight, pt, effects,
-		  charset);
-      LIST_LOOP (fonttail, device_font_list)
+	  LIST_LOOP (fonttail, device_font_list)
+	    {
+	      if (match_font (XSTRING_DATA (XCAR (XCAR (fonttail))),
+			      truename, truername))
+		break;
+	    }
+	}
+
+      if (NILP (fonttail))
 	{
-	  if (match_font (XSTRING_DATA (XCAR (fonttail)), truename,
-			  NULL))
-	    break;
+	  qxesprintf (truename, "%s:%s:%s:%s:%s",
+		      fontname, weight, points, effects, charset);
+
+	  LIST_LOOP (fonttail, device_font_list)
+	    {
+	      if (match_font (XSTRING_DATA (XCAR (XCAR (fonttail))),
+			      truename, truername))
+		break;
+	    }
 	}
+
       if (NILP (fonttail))
 	{
 	  maybe_signal_error (Qinvalid_argument, "No matching font",
 			      name_for_errors, Qfont, errb);
-	  return NULL;
+	  return 0;
 	}
+
+      if (!parse_font_spec (truername, hdc, name_for_errors,
+			    ERROR_ME_DEBUG_WARN, &logfont, fontname, weight,
+			    points, effects, charset))
+	signal_error (Qinternal_error, "Bad value in device font list?",
+		      build_intstring (truername));
     }
+  else if (!parse_font_spec (namestr, hdc, name_for_errors,
+			     errb, &logfont, fontname, weight, points,
+			     effects, charset))
+    return 0;
 
   if ((hfont = qxeCreateFontIndirect (&logfont)) == NULL)
     {
       maybe_signal_error (Qgui_error, "Couldn't create font",
 			  name_for_errors, Qfont, errb);
-      return NULL;
+      return 0;
     }
 
+  /* #### Truename will not have all its fields filled in when we have no
+     list of fonts.  Doesn't really matter now, since we always have one.
+     See above. */
+  qxesprintf (truename, "%s:%s:%s:%s:%s", fontname, weight,
+	      points, effects, charset);
+  
+  *truename_ret = build_intstring (truename);
   return hfont;
 }
 
-
 /*
  * This is a work horse for both mswindows_initialize_font_instance and
  * msprinter_initialize_font_instance.
@@ -1593,11 +1831,13 @@
   HFONT hfont, hfont2;
   TEXTMETRICW metrics;
   Ibyte *namestr = XSTRING_DATA (name);
+  Lisp_Object truename;
 
   hfont = create_hfont_from_font_spec (namestr, hdc, name, device_font_list,
-				       errb);
+				       errb, &truename);
+  f->truename = truename;
   f->data = xnew_and_zero (struct mswindows_font_instance_data);
-  FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f,0,0) = hfont;
+  FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f, 0, 0) = hfont;
 
   /* Some underlined fonts have the descent of one pixel more than their
      non-underlined counterparts. Font variants though are assumed to have
@@ -1700,7 +1940,8 @@
     {
       Ibyte fontname[MSW_FONTSIZE];
 
-      if (match_font (XSTRING_DATA (XCAR (fonttail)), XSTRING_DATA (pattern),
+      if (match_font (XSTRING_DATA (XCAR (XCAR (fonttail))),
+		      XSTRING_DATA (pattern),
 		      fontname))
 	result = Fcons (build_intstring (fontname), result);
     }
@@ -1708,118 +1949,29 @@
   return Fnreverse (result);
 }
 
-/* Fill in missing parts of a font spec. This is primarily intended as a
- * helper function for the functions below.
- * mswindows fonts look like:
- *	fontname[:[weight][ style][:pointsize[:effects]]][:charset]
- * A minimal mswindows font spec looks like:
- *	Courier New
- * A maximal mswindows font spec looks like:
- *	Courier New:Bold Italic:10:underline strikeout:Western
- * Missing parts of the font spec should be filled in with these values:
- *	Courier New:Regular:10::Western */
 static Lisp_Object
 mswindows_font_instance_truename (Lisp_Font_Instance *f, Error_Behavior errb)
 {
-  /* #### does not handle charset at end!!!  charset can be given even
-     when previous fields are not.
-
-     #### does not canonicalize given fields!  needs to be merged
-     with initialize_font_instance(). */
-
-  int nsep = 0;
-  Ibyte *ptr = (Ibyte *) XSTRING_DATA (f->name);
-  Ibyte *name = (Ibyte *) ALLOCA (XSTRING_LENGTH (f->name) + 19);
-
-  qxestrcpy (name, ptr);
-
-  while ((ptr = qxestrchr (ptr, ':')) != 0)
-    {
-      ptr++;
-      nsep++;
-    }
-
-  switch (nsep)
-    {
-    case 0:
-      qxestrcat_c (name, ":Regular:10::Western");
-      break;
-    case 1:
-      qxestrcat_c (name, ":10::Western");
-      break;
-    case 2:
-      qxestrcat_c (name, "::Western");
-      break;
-    case 3:
-      qxestrcat_c (name, ":Western");
-      break;
-    default:;
-    }
-
-  return build_intstring (name);
+  return f->truename;
 }
 
 #ifdef MULE
 
 static int
-mswindows_font_spec_matches_charset_stage_1 (const Ibyte *font_charset,
-					     Lisp_Object charset)
+mswindows_font_spec_matches_charset_stage_1 (struct device *d,
+					     Lisp_Object charset,
+					     const Ibyte *nonreloc,
+					     Lisp_Object reloc,
+					     Bytecount offset,
+					     Bytecount length)
 {
-  int i, ms_charset = 0;
-  CHARSETINFO info;
-  int font_code_page;
-  Lisp_Object charset_code_page;
-
-  /* Get code page from the font spec */
-  
-  for (i = 0; i < countof (charset_map); i++)
-    if (qxestrcasecmp_c (font_charset, charset_map[i].name) == 0)
-      {
-	ms_charset = charset_map[i].value;
-	break;
-      }
-  if (i == countof (charset_map))
-    return 0;
-
-  /* For border-glyph use */
-  if (ms_charset == SYMBOL_CHARSET)
-    ms_charset = ANSI_CHARSET;
-
-  if (!TranslateCharsetInfo ((DWORD *) ms_charset, &info, TCI_SRCCHARSET))
-    return 0;
-
-  font_code_page = info.ciACP;
-
-  /* Get code page for the charset */
-  charset_code_page = Fmswindows_charset_code_page (charset);
-  if (!INTP (charset_code_page))
-    return 0;
-
-  return font_code_page == XINT (charset_code_page);
-}
-
-static int
-mswindows_font_spec_matches_charset (struct device *d, Lisp_Object charset,
-				     const Ibyte *nonreloc,
-				     Lisp_Object reloc,
-				     Bytecount offset, Bytecount length)
-{
+  int i;
+  Lisp_Object charset_registry;
+  const Ibyte *font_charset;
   const Ibyte *the_nonreloc = nonreloc;
-  int i;
   const Ibyte *c;
   Bytecount the_length = length;
 
-/* The idea is that, when trying to find a suitable font for a character,
-   we first see if the character comes from one of the known charsets
-   listed above; if so, we try to find a font which is declared as being of
-   that charset (that's the last element of the font spec).  If so, this
-   means that the font is specifically designed for the charset, and we
-   prefer it.  However, there are only a limited number of defined
-   charsets, and new ones aren't being defined; so if we fail the first
-   stage, we search through each font looking at the Unicode subranges it
-   supports, to see if the character comes from that subrange.
-*/
-
   if (UNBOUNDP (charset))
     return 1;
 
@@ -1839,126 +1991,220 @@
       c = newc;
     }
 
-  if (i >= 4 && mswindows_font_spec_matches_charset_stage_1 (c, charset))
+  if (i < 4)
+    return 0;
+
+  font_charset = c;
+
+  /* For border-glyph use */
+  if (!qxestrcasecmp_c (font_charset, "symbol"))
+    font_charset = (const Ibyte *) "western";
+
+  /* Get code page for the charset */
+  charset_registry = Fmswindows_charset_registry (charset);
+  if (!STRINGP (charset_registry))
+    return 0;
+
+  return !qxestrcasecmp (XSTRING_DATA (charset_registry), font_charset);
+}
+
+/*
+
+1. handle standard mapping and inheritance vectors properly in Face-frob-property.
+2. finish impl of mswindows-charset-registry.
+3. see if everything works under fixup, now that i copied the stuff over.
+4. consider generalizing Face-frob-property to frob-specifier.
+5. maybe extract some of the flets out of Face-frob-property as useful specifier frobbing. 
+6. eventually this stuff's got to be checked in!!!!
+*/
+
+static int
+mswindows_font_spec_matches_charset_stage_2 (struct device *d,
+					     Lisp_Object charset,
+					     const Ibyte *nonreloc,
+					     Lisp_Object reloc,
+					     Bytecount offset,
+					     Bytecount length)
+{
+  const Ibyte *the_nonreloc = nonreloc;
+  FONTSIGNATURE fs;
+  FONTSIGNATURE *fsp = &fs;
+  struct gcpro gcpro1;
+  Lisp_Object fontsig;
+  Bytecount the_length = length;
+  int i;
+
+  if (UNBOUNDP (charset))
     return 1;
 
-  /* Stage 2. */
-  {
-    FONTSIGNATURE fs;
-    FONTSIGNATURE *fsp = &fs;
-    struct gcpro gcpro1;
-    Lisp_Object fontsig;
+  if (!the_nonreloc)
+    the_nonreloc = XSTRING_DATA (reloc);
+  fixup_internal_substring (nonreloc, reloc, offset, &the_length);
+  the_nonreloc += offset;
+
+  /* Get the list of Unicode subranges corresponding to the font.  This
+     is contained inside of FONTSIGNATURE data, obtained by calling
+     GetTextCharsetInfo on a font object, which we need to create from the
+     spec.  See if the FONTSIGNATURE data is already cached.  If not, get
+     it and cache it. */
+  if (!STRINGP (reloc) || the_nonreloc != XSTRING_DATA (reloc))
+    reloc = build_intstring (the_nonreloc);
+  GCPRO1 (reloc);
+  fontsig = Fgethash (reloc, Vfont_signature_data, Qunbound);
+
+  if (!UNBOUNDP (fontsig))
+    {
+      fsp = (FONTSIGNATURE *) XOPAQUE_DATA (fontsig);
+      UNGCPRO;
+    }
+  else
+    {
+      HDC hdc = CreateCompatibleDC (NULL);
+      Lisp_Object font_list = DEVICE_MSWINDOWS_FONTLIST (d);
+      Lisp_Object truename;
+      HFONT hfont = create_hfont_from_font_spec (the_nonreloc, hdc, Qnil,
+						 font_list,
+						 ERROR_ME_DEBUG_WARN,
+						 &truename);
 
-    /* Get the list of Unicode subranges corresponding to the font.  This
-      is contained inside of FONTSIGNATURE data, obtained by calling
-      GetTextCharsetInfo on a font object, which we need to create from the
-      spec.  See if the FONTSIGNATURE data is already cached.  If not, get
-      it and cache it. */
-    if (!STRINGP (reloc) || the_nonreloc != XSTRING_DATA (reloc))
-      reloc = build_intstring (the_nonreloc);
-    GCPRO1 (reloc);
-    fontsig = Fgethash (reloc, Vfont_signature_data, Qunbound);
+      if (!hfont || !(hfont = (HFONT) SelectObject (hdc, hfont)))
+	{
+	nope:
+	  DeleteDC (hdc);
+	  UNGCPRO;
+	  return 0;
+	}
+    
+      if (GetTextCharsetInfo (hdc, &fs, 0) == DEFAULT_CHARSET)
+	{
+	  SelectObject (hdc, hfont);
+	  goto nope;
+	}
+      SelectObject (hdc, hfont);
+      DeleteDC (hdc);
+      Fputhash (reloc, make_opaque (&fs, sizeof (fs)), Vfont_signature_data);
+      UNGCPRO;
+    }
 
-    if (!UNBOUNDP (fontsig))
+  {
+    int lowlim, highlim;
+    int dim, j, cp = -1;
+
+    /* Try to find a Unicode char in the charset.  #### This is somewhat
+       bogus.  See below.
+
+       #### Cache me baby!!!!!!!!!!!!!
+    */
+    get_charset_limits (charset, &lowlim, &highlim);
+    dim = XCHARSET_DIMENSION (charset);
+
+    if (dim == 1)
       {
-	fsp = (FONTSIGNATURE *) XOPAQUE_DATA (fontsig);
-	UNGCPRO;
+	for (i = lowlim; i <= highlim; i++)
+	  if ((cp = ichar_to_unicode (make_ichar (charset, i, 0))) >= 0)
+	    break;
       }
     else
       {
-	HDC hdc = CreateCompatibleDC (NULL);
-	Lisp_Object font_list = DEVICE_MSWINDOWS_FONTLIST (d);
-	HFONT hfont = create_hfont_from_font_spec (the_nonreloc, hdc, Qnil,
-						   font_list,
-						   ERROR_ME_DEBUG_WARN);
+	for (i = lowlim; i <= highlim; i++)
+	  for (j = lowlim; j <= highlim; j++)
+	    if ((cp = ichar_to_unicode (make_ichar (charset, i, j))) >= 0)
+	      break;
+      }
+      
+    if (cp < 0)
+      return 0;
 
-	if (!hfont || !(hfont = (HFONT) SelectObject (hdc, hfont)))
+    /* Check to see, for each subrange supported by the font,
+       whether the Unicode char is within that subrange.  If any match,
+       the font supports the char (whereby, the charset, bogusly). */
+      
+    for (i = 0; i < 128; i++)
+      {
+	if (fsp->fsUsb[i >> 5] & (1 << (i & 32)))
 	  {
-	  nope:
-	    DeleteDC (hdc);
-	    UNGCPRO;
-	    return 0;
+	    for (j = 0; j < unicode_subrange_table[i].no_subranges; j++)
+	      if (cp >= unicode_subrange_table[i].subranges[j].start &&
+		  cp <= unicode_subrange_table[i].subranges[j].end)
+		return 1;
 	  }
-    
-	if (GetTextCharsetInfo (hdc, &fs, 0) == DEFAULT_CHARSET)
-	  {
-	    SelectObject (hdc, hfont);
-	    goto nope;
-	  }
-	SelectObject (hdc, hfont);
-	DeleteDC (hdc);
-	Fputhash (reloc, make_opaque (&fs, sizeof (fs)), Vfont_signature_data);
-	UNGCPRO;
       }
 
-    {
-      int lowlim, highlim;
-      int dim, j, cp = -1;
-
-      /* Try to find a Unicode char in the charset.  #### This is somewhat
-	 bogus.  We should really be doing these checks on the char level,
-	 not the charset level.  There's no guarantee that a charset covers
-	 a single Unicode range.  Furthermore, this is extremely wasteful.
-	 We should be doing this when we're about to redisplay and already
-	 have the Unicode codepoints in hand.
-
-	 #### Cache me baby!!!!!!!!!!!!!
-       */
-      get_charset_limits (charset, &lowlim, &highlim);
-      dim = XCHARSET_DIMENSION (charset);
-
-      if (dim == 1)
-	{
-	  for (i = lowlim; i <= highlim; i++)
-	    if ((cp = ichar_to_unicode (make_ichar (charset, i, 0))) >= 0)
-	      break;
-	}
-      else
-	{
-	  for (i = lowlim; i <= highlim; i++)
-	    for (j = lowlim; j <= highlim; j++)
-	      if ((cp = ichar_to_unicode (make_ichar (charset, i, j))) >= 0)
-		break;
-	}
-      
-      if (cp < 0)
-	return 0;
-
-      /* Check to see, for each subrange supported by the font,
-	 whether the Unicode char is within that subrange.  If any match,
-	 the font supports the char (whereby, the charset, bogusly). */
-      
-      for (i = 0; i < 128; i++)
-	{
-	  if (fsp->fsUsb[i >> 5] & (1 << (i & 32)))
-	    {
-	      for (j = 0; j < unicode_subrange_table[i].no_subranges; j++)
-		if (cp >= unicode_subrange_table[i].subranges[j].start &&
-		    cp <= unicode_subrange_table[i].subranges[j].end)
-		  return 1;
-	    }
-	}
-
-      return 0;
-    }
+    return 0;
   }
 }
 
-/* find a font spec that matches font spec FONT and also matches
+/*
+  Given a truename font spec, does it match CHARSET?
+
+  We try two stages:
+
+  -- First see if the charset corresponds to one of the predefined Windows
+  charsets; if so, we see if the registry (that's the last element of the
+  font spec) is that same charset.  If so, this means that the font is
+  specifically designed for the charset, and we prefer it.
+
+  -- However, there are only a limited number of defined Windows charsets,
+  and new ones aren't being defined; so if we fail the first stage, we find
+  a character from the charset with a Unicode equivalent, and see if the
+  font can display this character.  we do that by retrieving the Unicode
+  ranges that the font supports, to see if the character comes from that
+  subrange.
+
+  #### Note: We really want to be doing all these checks at the character
+  level, not the charset level.  There's no guarantee that a charset covers
+  a single Unicode range.  Furthermore, this is extremely wasteful.  We
+  should be doing this when we're about to redisplay and already have the
+  Unicode codepoints in hand.
+*/
+
+static int
+mswindows_font_spec_matches_charset (struct device *d, Lisp_Object charset,
+				     const Ibyte *nonreloc,
+				     Lisp_Object reloc,
+				     Bytecount offset, Bytecount length,
+				     int stage)
+{
+  return stage ?
+     mswindows_font_spec_matches_charset_stage_2 (d, charset, nonreloc,
+						  reloc, offset, length)
+    : mswindows_font_spec_matches_charset_stage_1 (d, charset, nonreloc,
+						   reloc, offset, length);
+}
+
+
+/* Find a font spec that matches font spec FONT and also matches
    (the registry of) CHARSET. */
+
 static Lisp_Object
 mswindows_find_charset_font (Lisp_Object device, Lisp_Object font,
-			     Lisp_Object charset)
+			     Lisp_Object charset, int stage)
 {
   Lisp_Object fontlist, fonttail;
 
+  /* If FONT specifies a particular charset, this will only list fonts with
+     that charset; otherwise, it will list fonts with all charsets. */
   fontlist = mswindows_list_fonts (font, device);
-  LIST_LOOP (fonttail, fontlist)
+
+  if (!stage)
     {
-      if (mswindows_font_spec_matches_charset
-	  (XDEVICE (device), charset, 0, XCAR (fonttail), 0, -1))
-	return XCAR (fonttail);
+      LIST_LOOP (fonttail, fontlist)
+	{
+	  if (mswindows_font_spec_matches_charset_stage_1
+	      (XDEVICE (device), charset, 0, XCAR (fonttail), 0, -1))
+	    return XCAR (fonttail);
+	}
     }
+  else
+    {
+      LIST_LOOP (fonttail, fontlist)
+	{
+	  if (mswindows_font_spec_matches_charset_stage_2
+	      (XDEVICE (device), charset, 0, XCAR (fonttail), 0, -1))
+	    return XCAR (fonttail);
+	}
+    }
+
   return Qnil;
 }