XEmacs 21.2.28 "Hermes".
[chise/xemacs-chise.git.1] / src / objects-msw.c
index 255d3fd..fca8e11 100644 (file)
@@ -49,14 +49,17 @@ Boston, MA 02111-1307, USA.  */
 #include "device.h"
 #include "insdel.h"
 
-#ifdef __CYGWIN32__
+#if (defined(__CYGWIN32__) || defined(__MINGW32__)) && \
+       CYGWIN_VERSION_DLL_MAJOR < 21
 #define stricmp strcasecmp
+#define FONTENUMPROC FONTENUMEXPROC
+#define ntmTm ntmentm
 #endif
 
 typedef struct colormap_t 
 {
-  char *name;
-  COLORREF colorref;
+  CONST char *name;
+  CONST COLORREF colorref;
 } colormap_t;
 
 /* Colors from X11R6 "XConsortium: rgb.txt,v 10.41 94/02/20 18:39:36 rws Exp" */
@@ -721,6 +724,58 @@ static CONST colormap_t mswindows_X_color_map[] =
   {"LightGreen"                        , PALETTERGB (144, 238, 144) }
 };
 
+
+typedef struct fontmap_t 
+{
+  CONST char *name;
+  CONST int value;
+} fontmap_t;
+
+/* Default weight first, preferred names listed before synonyms */
+static CONST fontmap_t fontweight_map[] = 
+{
+  {"Regular"           , FW_REGULAR},  /* The standard font weight */
+  {"Thin"              , FW_THIN},
+  {"Extra Light"       , FW_EXTRALIGHT},
+  {"Ultra Light"       , FW_ULTRALIGHT},
+  {"Light"             , FW_LIGHT},
+  {"Normal"            , FW_NORMAL},
+  {"Medium"            , FW_MEDIUM},
+  {"Semi Bold"         , FW_SEMIBOLD},
+  {"Demi Bold"         , FW_DEMIBOLD},
+  {"Bold"              , FW_BOLD},     /* The standard bold font weight */
+  {"Extra Bold"                , FW_EXTRABOLD},
+  {"Ultra Bold"                , FW_ULTRABOLD},
+  {"Heavy"             , FW_HEAVY},
+  {"Black"             , FW_BLACK}
+};
+
+/* Default charset 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},
+  {"Symbol"            , SYMBOL_CHARSET},
+  {"Shift JIS"         , SHIFTJIS_CHARSET},    /* #### Name to be verified */
+  {"GB2312"            , GB2312_CHARSET},      /* #### Name to be verified */
+  {"Hanguel"           , HANGEUL_CHARSET},
+  {"Chinese Big 5"     , CHINESEBIG5_CHARSET}, /* #### Name to be verified */
+#if (WINVER >= 0x0400)
+  {"Johab"             , JOHAB_CHARSET},       /* #### Name to be verified */
+  {"Hebrew"            , HEBREW_CHARSET},      /* #### Name to be verified */
+  {"Arabic"            , ARABIC_CHARSET},      /* #### Name to be verified */
+  {"Greek"             , GREEK_CHARSET},
+  {"Turkish"           , TURKISH_CHARSET},
+  {"Vietnamese"                , VIETNAMESE_CHARSET},  /* #### Name to be verified */
+  {"Thai"              , THAI_CHARSET},        /* #### Name to be verified */
+  {"Central European"  , EASTEUROPE_CHARSET},
+  {"Cyrillic"          , RUSSIAN_CHARSET},
+  {"Mac"               , MAC_CHARSET},
+  {"Baltic"            , BALTIC_CHARSET},
+#endif
+  {"OEM/DOS"           , OEM_CHARSET}
+};
+
 \f
 /************************************************************************/
 /*                               helpers                                */
@@ -872,19 +927,172 @@ match_font (char *pattern1, char *pattern2, char *fontname)
   return 1;
 }
 
+
+
+
+\f
+/************************************************************************/
+/*                                 exports                              */
+/************************************************************************/
+
+struct font_enum_t
+{
+  HDC hdc;
+  Lisp_Object list;
+};
+
+static int CALLBACK
+font_enum_callback_2 (ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, 
+                     int FontType, struct font_enum_t *font_enum)
+{
+  char fontname[MSW_FONTSIZE];
+  Lisp_Object fontname_lispstr;
+  int i;
+
+  /*
+   * The enumerated font weights are not to be trusted because:
+   *  a) lpelfe->elfStyle is only filled in for TrueType fonts.
+   *  b) Not all Bold and Italic styles of all fonts (inluding some Vector,
+   *     Truetype and Raster fonts) are enumerated.
+   * I guess that fonts for which Bold and Italic styles are generated
+   * 'on-the-fly' are not enumerated. It would be overly restrictive to
+   * disallow Bold And Italic weights for these fonts, so we just leave
+   * weights unspecified. This means that we have to weed out duplicates of
+   * those fonts that do get enumerated with different weights.
+   */
+  if (FontType == 0 /*vector*/ || FontType == TRUETYPE_FONTTYPE)
+    /* Scalable, so leave pointsize blank */
+    sprintf (fontname, "%s::::", lpelfe->elfLogFont.lfFaceName);
+  else
+    /* Formula for pointsize->height from LOGFONT docs in Platform SDK */
+    sprintf (fontname, "%s::%d::", lpelfe->elfLogFont.lfFaceName,
+            MulDiv (lpntme->ntmTm.tmHeight - lpntme->ntmTm.tmInternalLeading,
+                    72, GetDeviceCaps (font_enum->hdc, LOGPIXELSY)));
+
+  /*
+   * The enumerated font character set strings are not to be trusted because
+   * lpelfe->elfScript is returned in the host language and not in English.
+   * We can't know a priori the translations of "Western", "Central European"
+   * etc into the host language, so we must use English. The same argument
+   * applies to the font weight string when matching fonts.
+   */
+  for (i=0; i<countof (charset_map); i++)
+    if (lpelfe->elfLogFont.lfCharSet == charset_map[i].value)
+      {
+       strcat (fontname, charset_map[i].name);
+       break;
+      }
+  if (i==countof (charset_map))
+    strcpy (fontname, charset_map[0].name);
+
+  /* Add the font name to the list if not already there */
+  fontname_lispstr = build_string (fontname);
+  if (NILP (memq_no_quit (fontname_lispstr, font_enum->list)))
+    font_enum->list = Fcons (fontname_lispstr, font_enum->list);
+
+  return 1;
+}
+
+static int CALLBACK
+font_enum_callback_1 (ENUMLOGFONTEX *lpelfe, NEWTEXTMETRICEX *lpntme, 
+                     int FontType, struct font_enum_t *font_enum)
+{
+  /* This function gets called once per facename per character set.
+   * We call a second callback to enumerate the fonts in each facename */
+  return EnumFontFamiliesEx (font_enum->hdc, &lpelfe->elfLogFont,
+                            (FONTENUMPROC) font_enum_callback_2,
+                            (LPARAM) font_enum, 0);
+}
+
+/*
+ * Enumerate the available on the HDC fonts and return a list of string
+ * font names.
+ */
+Lisp_Object
+mswindows_enumerate_fonts (HDC hdc)
+{
+  /* This cannot CG */
+  LOGFONT logfont;
+  struct font_enum_t font_enum;
+
+  assert (hdc!=NULL);
+  logfont.lfCharSet = DEFAULT_CHARSET;
+  logfont.lfFaceName[0] = '\0';
+  logfont.lfPitchAndFamily = DEFAULT_PITCH;
+  font_enum.hdc = hdc;
+  font_enum.list = Qnil;
+  EnumFontFamiliesEx (hdc, &logfont, (FONTENUMPROC) font_enum_callback_1,
+                     (LPARAM) (&font_enum), 0);
+  return font_enum.list;
+}
+
+static void
+mswindows_create_font_variant (Lisp_Font_Instance* f,
+                              int under, int strike)
+{
+  /* Cannot GC */
+
+  LOGFONT lf;
+  HFONT hfont;
+
+  assert (FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f, under, strike) == NULL);
+
+  if (GetObject (FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f, 0, 0),
+                sizeof (lf), (void*) &lf) == 0)
+    {
+      hfont = MSWINDOWS_BAD_HFONT;
+    }
+  else
+    {
+      lf.lfUnderline = under;
+      lf.lfStrikeOut = strike;
+
+      hfont = CreateFontIndirect (&lf);
+      if (hfont == NULL)
+       hfont = MSWINDOWS_BAD_HFONT;
+    }
+
+  FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f, under, strike) = hfont;
+}
+
+HFONT
+mswindows_get_hfont (Lisp_Font_Instance* f,
+                    int under, int strike)
+{
+  /* Cannot GC */
+  HFONT hfont;
+
+  if (FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f, under, strike) == NULL)
+    mswindows_create_font_variant (f, under, strike);
+
+  assert (FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f, under, strike) != NULL);
+
+  hfont = FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f, under, strike);
+
+  /* If strikeout/underline variant of the font could not be
+     created, then use the base version of the font */
+  if (hfont == MSWINDOWS_BAD_HFONT)
+    hfont = FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f, 0, 0);
+
+  assert (hfont != NULL && hfont != MSWINDOWS_BAD_HFONT);
+
+  return hfont;
+}
 \f
 /************************************************************************/
 /*                               methods                                */
 /************************************************************************/
 
 static int
-mswindows_initialize_color_instance (struct Lisp_Color_Instance *c, Lisp_Object name,
+mswindows_initialize_color_instance (Lisp_Color_Instance *c, Lisp_Object name,
                               Lisp_Object device, Error_behavior errb)
 {
   CONST char *extname;
   COLORREF color;
 
-  GET_C_STRING_CTEXT_DATA_ALLOCA (name, extname);
+  TO_EXTERNAL_FORMAT (LISP_STRING, name,
+                     C_STRING_ALLOCA, extname,
+                     Qctext);
   color = mswindows_string_to_color(extname);
   if (color != -1)
     {
@@ -892,22 +1100,21 @@ mswindows_initialize_color_instance (struct Lisp_Color_Instance *c, Lisp_Object
       COLOR_INSTANCE_MSWINDOWS_COLOR (c) = color;
       return 1;
     }
-  maybe_signal_simple_error ("unrecognized color", name, Qcolor, errb);
+  maybe_signal_simple_error ("Unrecognized color", name, Qcolor, errb);
   return(0);
 }
 
 #if 0
 static void
-mswindows_mark_color_instance (struct Lisp_Color_Instance *c,
-                        void (*markobj) (Lisp_Object))
+mswindows_mark_color_instance (Lisp_Color_Instance *c)
 {
 }
 #endif
 
 static void
-mswindows_print_color_instance (struct Lisp_Color_Instance *c,
-                         Lisp_Object printcharfun,
-                         int escapeflag)
+mswindows_print_color_instance (Lisp_Color_Instance *c,
+                               Lisp_Object printcharfun,
+                               int escapeflag)
 {
   char buf[32];
   COLORREF color = COLOR_INSTANCE_MSWINDOWS_COLOR (c);
@@ -917,7 +1124,7 @@ mswindows_print_color_instance (struct Lisp_Color_Instance *c,
 }
 
 static void
-mswindows_finalize_color_instance (struct Lisp_Color_Instance *c)
+mswindows_finalize_color_instance (Lisp_Color_Instance *c)
 {
   if (c->data)
     {
@@ -927,21 +1134,21 @@ mswindows_finalize_color_instance (struct Lisp_Color_Instance *c)
 }
 
 static int
-mswindows_color_instance_equal (struct Lisp_Color_Instance *c1,
-                         struct Lisp_Color_Instance *c2,
-                         int depth)
+mswindows_color_instance_equal (Lisp_Color_Instance *c1,
+                               Lisp_Color_Instance *c2,
+                               int depth)
 {
   return (COLOR_INSTANCE_MSWINDOWS_COLOR(c1) == COLOR_INSTANCE_MSWINDOWS_COLOR(c2));
 }
 
 static unsigned long
-mswindows_color_instance_hash (struct Lisp_Color_Instance *c, int depth)
+mswindows_color_instance_hash (Lisp_Color_Instance *c, int depth)
 {
-  return (unsigned long)(COLOR_INSTANCE_MSWINDOWS_COLOR(c));
+  return (unsigned long) COLOR_INSTANCE_MSWINDOWS_COLOR(c);
 }
 
 static Lisp_Object
-mswindows_color_instance_rgb_components (struct Lisp_Color_Instance *c)
+mswindows_color_instance_rgb_components (Lisp_Color_Instance *c)
 {
   COLORREF color = COLOR_INSTANCE_MSWINDOWS_COLOR (c);
   return list3 (make_int (GetRValue (color) * 257),
@@ -954,35 +1161,37 @@ mswindows_valid_color_name_p (struct device *d, Lisp_Object color)
 {
   CONST char *extname;
 
-  GET_C_STRING_CTEXT_DATA_ALLOCA (color, extname);
+  TO_EXTERNAL_FORMAT (LISP_STRING, color,
+                     C_STRING_ALLOCA, extname,
+                     Qctext);
   return (mswindows_string_to_color(extname)!=-1);
 }
 
 
 \f
 static void
-mswindows_finalize_font_instance (struct Lisp_Font_Instance *f)
-{
-  if (f->data)
-    {
-      DeleteObject(f->data);
-      f->data=0;
-    }
-}
+mswindows_finalize_font_instance (Lisp_Font_Instance *f);
 
+/*
+ * This is a work horse for both mswindows_initialize_font_instanc and
+ * msprinter_initialize_font_instance.
+ */
 static int
-mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object name,
-                                   Lisp_Object device, Error_behavior errb)
+initialize_font_instance (Lisp_Font_Instance *f, Lisp_Object name,
+                         Lisp_Object device_font_list, HDC hdc,
+                         Error_behavior errb)
 {
   CONST char *extname;
   LOGFONT logfont;
-  int fields;
+  int fields, i;
   int pt;
   char fontname[LF_FACESIZE], weight[LF_FACESIZE], *style, points[8];
   char effects[LF_FACESIZE], charset[LF_FACESIZE];
   char *c;
-  
-  GET_C_STRING_CTEXT_DATA_ALLOCA (f->name, extname);
+  HFONT hfont, holdfont;
+  TEXTMETRIC metrics;
+
+  extname = XSTRING_DATA (name);
 
   /*
    * mswindows fonts look like:
@@ -1003,12 +1212,12 @@ mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object na
   /* This function is implemented in a fairly ad-hoc manner.
    * The general idea is to validate and canonicalize each of the above fields
    * at the same time as we build up the win32 LOGFONT structure. This enables
-   * us to use math_font() on a canonicalized font string to check the
+   * us to use match_font() on a canonicalized font string to check the
    * availability of the requested font */
 
-  if (fields<0)
+  if (fields < 0)
   {
-    maybe_signal_simple_error ("Invalid font", f->name, Qfont, errb);
+    maybe_signal_simple_error ("Invalid font", name, Qfont, errb);
     return (0);
   }
 
@@ -1019,13 +1228,13 @@ mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object na
   }
   else
   {
-    maybe_signal_simple_error ("Must specify a font name", f->name, Qfont, errb);
+    maybe_signal_simple_error ("Must specify a font name", name, Qfont, errb);
     return (0);
   }
 
   /* weight */
   if (fields < 2)
-    strcpy (weight, "Regular");
+    strcpy (weight, fontweight_map[0].name);
 
   /* Maybe split weight into weight and style */
   if ((c=strchr(weight, ' ')))
@@ -1036,37 +1245,26 @@ mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object na
   else
     style = NULL;
 
-#define FROB(wgt)                              \
-  if (stricmp (weight, #wgt) == 0)             \
-    logfont.lfWeight = FW_##wgt
-
-  FROB (REGULAR);
-  else FROB (THIN);
-  else FROB (EXTRALIGHT);
-  else FROB (ULTRALIGHT);
-  else FROB (LIGHT);
-  else FROB (NORMAL);
-  else FROB (MEDIUM);
-  else FROB (SEMIBOLD);
-  else FROB (DEMIBOLD);
-  else FROB (BOLD);
-  else FROB (EXTRABOLD);
-  else FROB (ULTRABOLD);
-  else FROB (HEAVY);
-  else FROB (BLACK);
-  else if (!style)
-    {
-      logfont.lfWeight = FW_REGULAR;
-      style = weight;  /* May have specified style without weight */
-    }
-  else
+  for (i=0; i<countof (fontweight_map); i++)
+    if (!stricmp (weight, fontweight_map[i].name))
+      {        
+       logfont.lfWeight = fontweight_map[i].value;
+       break;
+      }
+  if (i == countof (fontweight_map))   /* No matching weight */
     {
-      maybe_signal_simple_error ("Invalid font weight", f->name, Qfont, errb);
-      return (0);
+      if (!style)
+       {
+         logfont.lfWeight = FW_REGULAR;
+         style = weight;       /* May have specified style without weight */
+       }
+      else
+       {
+         maybe_signal_simple_error ("Invalid font weight", name, Qfont, errb);
+         return (0);
+       }
     }
 
-#undef FROB
-
   if (style)
     {
       /* #### what about oblique? */
@@ -1074,7 +1272,7 @@ mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object na
        logfont.lfItalic = TRUE;
       else
       {
-        maybe_signal_simple_error ("Invalid font weight or style", f->name, Qfont, errb);
+        maybe_signal_simple_error ("Invalid font weight or style", name, Qfont, errb);
        return (0);
       }
 
@@ -1089,12 +1287,12 @@ mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object na
     pt = 10;   /* #### Should we reject strings that don't specify a size? */
   else if ((pt=atoi(points)) == 0)
     {
-      maybe_signal_simple_error ("Invalid font pointsize", f->name, Qfont, errb);
+      maybe_signal_simple_error ("Invalid font pointsize", name, Qfont, errb);
       return (0);
     }
 
   /* Formula for pointsize->height from LOGFONT docs in MSVC5 Platform SDK */
-  logfont.lfHeight = -MulDiv(pt, DEVICE_MSWINDOWS_LOGPIXELSY(XDEVICE (device)), 72);
+  logfont.lfHeight = -MulDiv(pt, GetDeviceCaps (hdc, LOGPIXELSY), 72);
   logfont.lfWidth = 0;
 
   /* Effects */
@@ -1119,8 +1317,7 @@ mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object na
        logfont.lfStrikeOut = TRUE;
       else
         {
-          maybe_signal_simple_error ("Invalid font effect", f->name,
-                                    Qfont, errb);
+          maybe_signal_simple_error ("Invalid font effect", name, Qfont, errb);
          return (0);
        }
 
@@ -1132,7 +1329,7 @@ mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object na
            logfont.lfStrikeOut = TRUE;
          else
            {
-             maybe_signal_simple_error ("Invalid font effect", f->name,
+             maybe_signal_simple_error ("Invalid font effect", name,
                                         Qfont, errb);
              return (0);
            }
@@ -1152,81 +1349,32 @@ mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object na
   else
     effects[0] = '\0';
 
-#define FROB(cs)                               \
-  else if (stricmp (charset, #cs) == 0)                \
-    logfont.lfCharSet = cs##_CHARSET
-
-  /* Charset aliases. Hangeul = Hangul is defined in windows.h.
-     We do not use the name "russian", only "cyrillic", as it is
-     the common name of this charset, used in other languages
-     than Russian. */
-#define CYRILLIC_CHARSET RUSSIAN_CHARSET
-#define CENTRALEUROPEAN_CHARSET EASTEUROPE_CHARSET
-#define CENTRALEUROPEAN_CHARSET EASTEUROPE_CHARSET
-
+  /* Charset */
   /* charset can be specified even if earlier fields havn't been */
-  if ((fields < 5) && (c=strchr (extname, ':')) && (c=strchr (c+1, ':')) &&
-      (c=strchr (c+1, ':')) && (c=strchr (c+1, ':')))
+  if (fields < 5)
     {
-      strncpy (charset, c+1, LF_FACESIZE);
-      charset[LF_FACESIZE-1] = '\0';
-    }
-  else
-    charset[0] = '\0';
-         
-  if (charset[0] == '\0' || (stricmp (charset, "ansi") == 0) ||
-      (stricmp (charset, "western") == 0))
-    {
-      logfont.lfCharSet = ANSI_CHARSET;
-      strcpy (charset, "western");
-    }
-  FROB (SYMBOL);
-  FROB (SHIFTJIS);
-  FROB (GB2312);
-  FROB (HANGEUL);
-  FROB (CHINESEBIG5);
-  FROB (JOHAB);
-  FROB (HEBREW);
-  FROB (ARABIC);
-  FROB (GREEK);
-  FROB (TURKISH);
-  FROB (THAI);
-  FROB (EASTEUROPE);
-  FROB (CENTRALEUROPEAN);
-  FROB (CYRILLIC);
-  FROB (MAC);
-  FROB (BALTIC);
-  else if (stricmp (charset, "oem/dos") == 0)
-    logfont.lfCharSet = OEM_CHARSET;
-  else
-    {
-      maybe_signal_simple_error ("Invalid charset", f->name, Qfont, errb);
-      return 0;
+      if ((c=strchr (extname, ':')) && (c=strchr (c+1, ':')) &&
+         (c=strchr (c+1, ':')) && (c=strchr (c+1, ':')))
+       {
+         strncpy (charset, c+1, LF_FACESIZE);
+         charset[LF_FACESIZE-1] = '\0';
+       }
+      else
+       strcpy (charset, charset_map[0].name);
     }
 
-#undef FROB
-
-  /* Windows will silently substitute a default font if the fontname 
-   * specifies a non-existent font. So we check the font against the device's
-   * list of font patterns to make sure that at least one of them matches */
-  {
-    struct mswindows_font_enum *fontlist;
-    char truename[MSW_FONTSIZE];
-    int done = 0;
-    
-    sprintf (truename, "%s:%s:%d:%s:%s", fontname, weight, pt, effects, charset);
-    fontlist = DEVICE_MSWINDOWS_FONTLIST (XDEVICE (device));
-    while (fontlist && !done)
-      {
-        done = match_font (fontlist->fontname, truename, NULL);
-        fontlist = fontlist->next;
-      }
-    if (!done)
+  for (i=0; i<countof (charset_map); i++)
+    if (!stricmp (charset, charset_map[i].name))
       {
-       maybe_signal_simple_error ("No matching font", f->name, Qfont, errb);
-       return 0;
+       logfont.lfCharSet = charset_map[i].value;
+       break;
       }
-  }
+
+  if (i == countof (charset_map))      /* No matching charset */
+    {
+      maybe_signal_simple_error ("Invalid charset", name, Qfont, errb);
+      return 0;
+    }
 
   /* Misc crud */
   logfont.lfEscapement = logfont.lfOrientation = 0;
@@ -1239,79 +1387,193 @@ mswindows_initialize_font_instance (struct Lisp_Font_Instance *f, Lisp_Object na
   logfont.lfClipPrecision = CLIP_STROKE_PRECIS;
   logfont.lfQuality = PROOF_QUALITY;
 #endif
-  /* Default to monospaced if the specified fontname doesn't exist.
-   * The match_font calls above should mean that this can't happen. */
+  /* Default to monospaced if the specified fontname doesn't exist. */
   logfont.lfPitchAndFamily = FF_MODERN;
 
-  if ((f->data = CreateFontIndirect(&logfont)) == NULL)
+  /* Windows will silently substitute a default font if the fontname
+   specifies a non-existent font. So we check the font against the
+   device's list of font patterns to make sure that at least one of
+   them matches.
+
+   Personally, I do not like the idea - it is better to come out with
+   some font than completely without one. The diversity of printer
+   fonts is much greater than that of screen font. We can tread on
+   that. -- kkm. */
+
+  if (!NILP (device_font_list))
+    {
+      Lisp_Object fonttail;
+      char truename[MSW_FONTSIZE];
+
+      sprintf (truename, "%s:%s:%d:%s:%s", fontname, weight, pt, effects, charset);
+      LIST_LOOP (fonttail, device_font_list)
+       {
+         if (match_font (XSTRING_DATA (XCAR (fonttail)), truename, NULL))
+           break;
+       }
+      if (NILP (fonttail))
+       {
+         maybe_signal_simple_error ("No matching font", name, Qfont, errb);
+         return 0;
+       }
+    }
+
+  if ((hfont = CreateFontIndirect(&logfont)) == NULL)
   {
-    maybe_signal_simple_error ("Couldn't create font", f->name, Qfont, errb);
+    maybe_signal_simple_error ("Couldn't create font", name, Qfont, errb);
     return 0;
   }
 
-  {
-    HDC hdc;
-    HFONT holdfont;
-    TEXTMETRIC metrics;
+  f->data = xnew_and_zero (struct mswindows_font_instance_data);
+  FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f,0,0) = hfont;
+  
+  holdfont = SelectObject(hdc, hfont);
+  if (!holdfont)
+    {
+      mswindows_finalize_font_instance (f);
+      maybe_signal_simple_error ("Couldn't map font", name, Qfont, errb);
+      return 0;
+    }
 
-    hdc = CreateCompatibleDC (NULL);
-    if (hdc)
-      {
-       holdfont = SelectObject(hdc, f->data);
-       if (holdfont)
-         {
-           GetTextMetrics (hdc, &metrics);
-           SelectObject(hdc, holdfont);
-           DeleteDC (hdc);
-           f->width = (unsigned short) metrics.tmAveCharWidth;
-           f->height = (unsigned short) metrics.tmHeight;
-           f->ascent = (unsigned short) metrics.tmAscent;
-           f->descent = (unsigned short) metrics.tmDescent;
-           f->proportional_p = (metrics.tmPitchAndFamily & TMPF_FIXED_PITCH);
-           return 1;
-         }
-       DeleteDC (hdc);
-      }
-    mswindows_finalize_font_instance (f);
-    maybe_signal_simple_error ("Couldn't map font", f->name, Qfont, errb);
-  }
-  return 0;
+  GetTextMetrics (hdc, &metrics);
+  SelectObject(hdc, holdfont);
+
+  f->width = (unsigned short) metrics.tmAveCharWidth;
+  f->height = (unsigned short) metrics.tmHeight;
+  /* Font variant metrics hack. The problem is that in Windows
+     some underlined fonts have the descent of one pixel more
+     than their non-underlined counterparts.  Font variants
+     though are assumed to have identical metrics. Lowering
+     the font's baseline one pixel down cures the problem, and
+     is visually undetectable. - kkm */
+  f->ascent = (unsigned short) metrics.tmAscent - 1;
+  f->descent = (unsigned short) metrics.tmDescent + 1;
+  f->proportional_p = (metrics.tmPitchAndFamily & TMPF_FIXED_PITCH);
+
+  return 1;
+}
+
+static int
+mswindows_initialize_font_instance (Lisp_Font_Instance *f, Lisp_Object name,
+                                   Lisp_Object device, Error_behavior errb)
+{
+  HDC hdc = CreateCompatibleDC (NULL);
+  Lisp_Object font_list = DEVICE_MSWINDOWS_FONTLIST (XDEVICE (device));
+  int res = initialize_font_instance (f, name, font_list, hdc, errb);
+  DeleteDC (hdc);
+  return res;
+}
+
+static int
+msprinter_initialize_font_instance (Lisp_Font_Instance *f, Lisp_Object name,
+                                   Lisp_Object device, Error_behavior errb)
+{
+  HDC hdc = DEVICE_MSPRINTER_HDC (XDEVICE (device));
+  Lisp_Object font_list = DEVICE_MSPRINTER_FONTLIST (XDEVICE (device));
+  return initialize_font_instance (f, name, font_list, hdc, errb);
+}
+
+static void
+mswindows_finalize_font_instance (Lisp_Font_Instance *f)
+{
+  int i;
+
+  if (f->data)
+    {
+      for (i = 0; i < MSWINDOWS_NUM_FONT_VARIANTS; i++)
+       {
+         if (FONT_INSTANCE_MSWINDOWS_HFONT_I (f, i) != NULL
+             && FONT_INSTANCE_MSWINDOWS_HFONT_I (f, i) != MSWINDOWS_BAD_HFONT)
+           DeleteObject (FONT_INSTANCE_MSWINDOWS_HFONT_I (f, i));
+       }
+
+      xfree (f->data);
+      f->data = 0;
+   }
 }
 
 #if 0
 static void
-mswindows_mark_font_instance (struct Lisp_Font_Instance *f,
-                       void (*markobj) (Lisp_Object))
+mswindows_mark_font_instance (Lisp_Font_Instance *f)
 {
 }
 #endif
 
 static void
-mswindows_print_font_instance (struct Lisp_Font_Instance *f,
-                        Lisp_Object printcharfun,
-                        int escapeflag)
+mswindows_print_font_instance (Lisp_Font_Instance *f,
+                              Lisp_Object printcharfun,
+                              int escapeflag)
 {
+  char buf[10];
+  sprintf (buf, " 0x%lx", 
+          (unsigned long)FONT_INSTANCE_MSWINDOWS_HFONT_VARIANT (f,0,0));
+  write_c_string (buf, printcharfun);
 }
 
 static Lisp_Object
 mswindows_list_fonts (Lisp_Object pattern, Lisp_Object device)
 {
-  Lisp_Object result = Qnil;
-  struct mswindows_font_enum *fontlist;
-  char fontname[MSW_FONTSIZE], *extpattern;
+  Lisp_Object fonttail, result = Qnil;
+  char *extpattern;
 
-  GET_C_STRING_CTEXT_DATA_ALLOCA (pattern, extpattern);
-  fontlist = DEVICE_MSWINDOWS_FONTLIST (XDEVICE (device));
-  while (fontlist)
+  TO_EXTERNAL_FORMAT (LISP_STRING, pattern,
+                     C_STRING_ALLOCA, extpattern,
+                     Qctext);
+
+  LIST_LOOP (fonttail, DEVICE_MSWINDOWS_FONTLIST (XDEVICE (device)))
     {
-      if (match_font (fontlist->fontname, extpattern, fontname))
-        result = Fcons (build_string (fontname), result);
-      fontlist = fontlist->next;
+      if (match_font (XSTRING_DATA (XCAR (fonttail)), extpattern, NULL))
+       result = Fcons (XCAR (fonttail), result);
     }
 
   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)
+{
+  int nsep=0;
+  char *name = (char *) XSTRING_DATA (f->name);
+  char* ptr = name;
+  char* extname = alloca (strlen (name) + 19);
+  strcpy (extname, name);
+
+  while ((ptr = strchr (ptr, ':')) != 0)
+    {
+      ptr++;
+      nsep++;
+    }
+
+  switch (nsep)
+    {
+    case 0:
+      strcat (extname, ":Regular:10::Western");
+      break;
+    case 1:
+      strcat (extname, ":10::Western");
+      break;
+    case 2:
+      strcat (extname, "::Western");
+      break;
+    case 3:
+      strcat (extname, ":Western");
+      break;
+    default:;
+    }
+  
+  return build_ext_string (extname, Qnative);
+}
+
 #ifdef MULE
 
 static int
@@ -1386,12 +1648,35 @@ console_type_create_objects_mswindows (void)
 /*  CONSOLE_HAS_METHOD (mswindows, mark_font_instance); */
   CONSOLE_HAS_METHOD (mswindows, print_font_instance);
   CONSOLE_HAS_METHOD (mswindows, finalize_font_instance);
-/*  CONSOLE_HAS_METHOD (mswindows, font_instance_truename); */
+  CONSOLE_HAS_METHOD (mswindows, font_instance_truename); 
   CONSOLE_HAS_METHOD (mswindows, list_fonts);
 #ifdef MULE
   CONSOLE_HAS_METHOD (mswindows, font_spec_matches_charset);
   CONSOLE_HAS_METHOD (mswindows, find_charset_font);
 #endif
+
+  /* Printer methods - delegate most to windows methods,
+     since graphical objects behave the same way. */
+
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, initialize_color_instance);
+/*  CONSOLE_INHERITS_METHOD (msprinter, mswindows, mark_color_instance); */
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, print_color_instance);
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, finalize_color_instance);
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, color_instance_equal);
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, color_instance_hash);
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, color_instance_rgb_components);
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, valid_color_name_p);
+
+  CONSOLE_HAS_METHOD (msprinter, initialize_font_instance);
+/*  CONSOLE_INHERITS_METHOD (msprinter, mswindows, mark_font_instance); */
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, print_font_instance);
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, finalize_font_instance);
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, font_instance_truename); 
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, list_fonts);
+#ifdef MULE
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, font_spec_matches_charset);
+  CONSOLE_INHERITS_METHOD (msprinter, mswindows, find_charset_font);
+#endif
 }
 
 void