changeset 92409:8171649adf8a

(Quniscribe, QCformat): New symbols. (syms_of_w32font): Define them. (w32font_has_char): Indicate uncertainty. (w32font_encode_char): Encode as glyph point. Make static. (recompute_cached_metrics): New function. (w32font_open_internal): Use it. Set font to use glyph points initially. Set format based on type of font. (w32font_text_extents, w32font_draw): Optionally use glyph points. (w32_enumfont_pattern_entity): Accept backend arg. Set type based on it. Set format based on information available here. (add_font_entity_to_list): Identify backend based on opentype_only.
author Jason Rumney <jasonr@gnu.org>
date Mon, 03 Mar 2008 00:31:18 +0000
parents a371504924ef
children 9fb51b883c0c
files src/w32font.c
diffstat 1 files changed, 169 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/src/w32font.c	Mon Mar 03 00:31:03 2008 +0000
+++ b/src/w32font.c	Mon Mar 03 00:31:18 2008 +0000
@@ -45,6 +45,8 @@
 extern struct font_driver w32font_driver;
 
 Lisp_Object Qgdi;
+Lisp_Object Quniscribe;
+static Lisp_Object QCformat;
 static Lisp_Object Qmonospace, Qsansserif, Qmono, Qsans, Qsans_serif;
 static Lisp_Object Qserif, Qscript, Qdecorative;
 static Lisp_Object Qraster, Qoutline, Qunknown;
@@ -78,9 +80,7 @@
 static Lisp_Object font_supported_scripts P_ ((FONTSIGNATURE * sig));
 static int w32font_full_name P_ ((LOGFONT * font, Lisp_Object font_obj,
                                   int pixel_size, char *name, int nbytes));
-
-/* From old font code in w32fns.c */
-char * w32_to_x_charset P_ ((int charset, char * matching));
+static void recompute_cached_metrics P_ ((HDC dc, struct font * font));
 
 static Lisp_Object w32_registry P_ ((LONG w32_charset));
 
@@ -117,12 +117,9 @@
    style variations if the font name is not specified.  */
 static void list_all_matching_fonts P_ ((struct font_callback_data *match));
 
+/* From old font code in w32fns.c */
+char * w32_to_x_charset P_ ((int charset, char * matching));
 
-/* MingW headers only define this when _WIN32_WINNT >= 0x0500, but we
-   target older versions.  */
-#ifndef GGI_MARK_NONEXISTING_GLYPHS
-#define GGI_MARK_NONEXISTING_GLYPHS 1
-#endif
 
 static int
 memq_no_quit (elt, list)
@@ -263,20 +260,74 @@
 
   script = CHAR_TABLE_REF (Vchar_script_table, c);
 
-  return (memq_no_quit (script, supported_scripts)) ? 1 : 0;
+  return (memq_no_quit (script, supported_scripts)) ? -1 : 0;
 }
 
 /* w32 implementation of encode_char for font backend.
    Return a glyph code of FONT for characer C (Unicode code point).
    If FONT doesn't have such a glyph, return FONT_INVALID_CODE.  */
-unsigned
+static unsigned
 w32font_encode_char (font, c)
      struct font *font;
      int c;
 {
-  /* Avoid unneccesary conversion - all the Win32 APIs will take a unicode
-     character.  */
-  return c;
+  struct frame *f;
+  HDC dc;
+  HFONT old_font;
+  DWORD retval;
+  GCP_RESULTSW result;
+  wchar_t in[2];
+  wchar_t out[2];
+  int len;
+  struct w32font_info *w32_font = (struct w32font_info *) font;
+
+  /* If glyph indexing is not working for this font, just return the
+     unicode code-point.  */
+  if (!w32_font->glyph_idx)
+    return c;
+
+  if (c > 0xFFFF)
+    {
+      /* TODO: Encode as surrogate pair and lookup the glyph.  */
+      return FONT_INVALID_CODE;
+    }
+  else
+    {
+      in[0] = (wchar_t) c;
+      len = 1;
+    }
+
+  bzero (&result, sizeof (result));
+  result.lStructSize = sizeof (result);
+  result.lpGlyphs = out;
+  result.nGlyphs = 2;
+
+  f = XFRAME (selected_frame);
+
+  dc = get_frame_dc (f);
+  old_font = SelectObject (dc, ((W32FontStruct *) (font->font.font))->hfont);
+
+  retval = GetCharacterPlacementW (dc, in, len, 0, &result, 0);
+
+  SelectObject (dc, old_font);
+  release_frame_dc (f, dc);
+
+  if (retval)
+    {
+      if (result.nGlyphs != 1 || !result.lpGlyphs[0])
+        return FONT_INVALID_CODE;
+      return result.lpGlyphs[0];
+    }
+  else
+    {
+      int i;
+      /* Mark this font as not supporting glyph indices. This can happen
+         on Windows9x, and maybe with non-Truetype fonts on NT etc.  */
+      w32_font->glyph_idx = 0;
+      recompute_cached_metrics (dc, font);
+
+      return c;
+    }
 }
 
 /* w32 implementation of text_extents for font backend.
@@ -308,6 +359,7 @@
     {
       GLYPHMETRICS gm;
       MAT2 transform;
+      struct w32font_info *w32_font = (struct w32font_info *) font;
 
       /* Set transform to the identity matrix.  */
       bzero (&transform, sizeof (transform));
@@ -320,11 +372,11 @@
 
       for (i = 0; i < nglyphs; i++)
         {
-          if (*(code + i) < 128 && *(code + i) > 32)
+          if (*(code + i) < 128)
             {
               /* Use cached metrics for ASCII.  */
               struct font_metrics *char_metric
-                = &((struct w32font_info *)font)->ascii_metrics[*(code+i)-32];
+                = &w32_font->ascii_metrics[*(code+i)];
 
               /* If we couldn't get metrics when caching, use fallback.  */
               if (char_metric->width == 0)
@@ -346,8 +398,11 @@
                   old_font = SelectObject (dc, ((W32FontStruct *)
                                                 (font->font.font))->hfont);
                 }
-              if (GetGlyphOutlineW (dc, *(code + i), GGO_METRICS, &gm, 0,
-                                    NULL, &transform) != GDI_ERROR)
+              if (GetGlyphOutlineW (dc, *(code + i),
+                                    GGO_METRICS
+                                      | w32_font->glyph_idx
+                                        ? GGO_GLYPH_INDEX : 0,
+                                    &gm, 0, NULL, &transform) != GDI_ERROR)
                 {
                   int new_val = metrics->width + gm.gmBlackBoxX
                     + gm.gmptGlyphOrigin.x;
@@ -362,6 +417,20 @@
                 }
               else
                 {
+                  if (w32_font->glyph_idx)
+                    {
+                      /* Disable glyph indexing for this font, as we can't
+                         handle the metrics.  Abort this run, our recovery
+                         strategies rely on having unicode code points here.
+                         This will cause a glitch in display, but in practice,
+                         any problems should be caught when initialising the
+                         metrics cache.  */
+                      w32_font->glyph_idx = 0;
+                      recompute_cached_metrics (dc, font);
+                      SelectObject (dc, old_font);
+                      release_frame_dc (f, dc);
+                      return 0;
+                    }
                   /* Rely on an estimate based on the overall font metrics.  */
                   break;
                 }
@@ -449,8 +518,11 @@
      struct glyph_string *s;
      int from, to, x, y, with_background;
 {
-  UINT options = 0;
+  UINT options;
   HRGN orig_clip;
+  struct w32font_info *w32font = (struct w32font_info *) s->face->font_info;
+
+  options = w32font->glyph_idx;
 
   /* Save clip region for later restoration.  */
   GetClipRgn(s->hdc, orig_clip);
@@ -709,34 +781,12 @@
   GetTextMetrics (dc, &w32_font->metrics);
 
   /* Cache ASCII metrics.  */
-  {
-    GLYPHMETRICS gm;
-    MAT2 transform;
-    int i;
-
-    bzero (&transform, sizeof (transform));
-    transform.eM11.value = 1;
-    transform.eM22.value = 1;
-
-    for (i = 0; i < 96; i++)
-      {
-        struct font_metrics* char_metric = &w32_font->ascii_metrics[i];
-
-        if (GetGlyphOutlineW (dc, i + 32, GGO_METRICS, &gm, 0,
-                              NULL, &transform) != GDI_ERROR)
-          {
-            char_metric->lbearing = -gm.gmptGlyphOrigin.x;
-            char_metric->rbearing = gm.gmBlackBoxX + gm.gmptGlyphOrigin.x;
-            char_metric->width = gm.gmCellIncX;
-            char_metric->ascent = -gm.gmptGlyphOrigin.y;
-            char_metric->descent = gm.gmBlackBoxY + gm.gmptGlyphOrigin.y;
-          }
-        else
-          char_metric->width = 0;
-      }
-  }
+  recompute_cached_metrics (dc, font);
   SelectObject (dc, old_font);
   release_frame_dc (f, dc);
+
+  w32_font->glyph_idx = ETO_GLYPH_INDEX;
+
   /* W32FontStruct - we should get rid of this, and use the w32font_info
      struct for any W32 specific fields. font->font.font can then be hfont.  */
   font->font.font = xmalloc (sizeof (W32FontStruct));
@@ -790,7 +840,20 @@
   font->entity = font_entity;
   font->pixel_size = size;
   font->driver = &w32font_driver;
-  font->format = Qgdi;
+  /* Use format cached during list, as the information we have access to
+     here is incomplete.  */
+  extra = AREF (font_entity, FONT_EXTRA_INDEX);
+  if (CONSP (extra))
+    {
+      val = assq_no_quit (QCformat, extra);
+      if (CONSP (val))
+        font->format = XCDR (val);
+      else
+        font->format = Qunknown;
+    }
+  else
+    font->format = Qunknown;
+
   font->file_name = NULL;
   font->encoding_charset = -1;
   font->repertory_charset = -1;
@@ -859,20 +922,22 @@
 /* Convert an enumerated Windows font to an Emacs font entity.  */
 static Lisp_Object
 w32_enumfont_pattern_entity (frame, logical_font, physical_font,
-                             font_type, requested_font)
+                             font_type, requested_font, backend)
      Lisp_Object frame;
      ENUMLOGFONTEX *logical_font;
      NEWTEXTMETRICEX *physical_font;
      DWORD font_type;
      LOGFONT *requested_font;
+     Lisp_Object backend;
 {
   Lisp_Object entity, tem;
   LOGFONT *lf = (LOGFONT*) logical_font;
   BYTE generic_type;
+  BYTE full_type = physical_font->ntmTm.ntmFlags;
 
   entity = Fmake_vector (make_number (FONT_ENTITY_MAX), Qnil);
 
-  ASET (entity, FONT_TYPE_INDEX, Qgdi);
+  ASET (entity, FONT_TYPE_INDEX, backend);
   ASET (entity, FONT_FRAME_INDEX, frame);
   ASET (entity, FONT_REGISTRY_INDEX, w32_registry (lf->lfCharSet));
   ASET (entity, FONT_OBJLIST_INDEX, Qnil);
@@ -939,6 +1004,24 @@
                       font_supported_scripts (&physical_font->ntmFontSig));
     }
 
+  /* This information is not fully available when opening fonts, so
+     save it here.  Only Windows 2000 and later return information
+     about opentype and type1 fonts, so need a fallback for detecting
+     truetype so that this information is not any worse than we could
+     have obtained later.  */
+  if (full_type & NTM_TT_OPENTYPE || font_type & TRUETYPE_FONTTYPE)
+    tem = intern ("truetype");
+  else if (full_type & NTM_TYPE1)
+    tem = intern ("type1");
+  else if (full_type & NTM_PS_OPENTYPE)
+    tem = intern ("postscript");
+  else if (font_type & RASTER_FONTTYPE)
+    tem = intern ("w32bitmap");
+  else
+    tem = intern ("w32vector");
+
+  font_put_extra (entity, QCformat, tem);
+
   return entity;
 }
 
@@ -1166,7 +1249,9 @@
       Lisp_Object entity
         = w32_enumfont_pattern_entity (match_data->frame, logical_font,
                                        physical_font, font_type,
-                                       &match_data->pattern);
+                                       &match_data->pattern,
+                                       match_data->opentype_only
+                                         ? Quniscribe : Qgdi);
       if (!NILP (entity))
         match_data->list = Fcons (entity, match_data->list);
     }
@@ -1615,6 +1700,40 @@
   return (p - name);
 }
 
+
+static void
+recompute_cached_metrics (dc, font)
+     HDC dc;
+     struct font *font;
+{
+  GLYPHMETRICS gm;
+  MAT2 transform;
+  int i;
+  struct w32font_info *w32_font;
+
+  bzero (&transform, sizeof (transform));
+  transform.eM11.value = 1;
+  transform.eM22.value = 1;
+  
+  for (i = 0; i < 128; i++)
+    {
+      struct font_metrics* char_metric = &w32_font->ascii_metrics[i];
+
+      if (GetGlyphOutlineW (dc, i + 32, GGO_METRICS
+                            | w32_font->glyph_idx ? GGO_GLYPH_INDEX : 0,
+                            &gm, 0, NULL, &transform) != GDI_ERROR)
+        {
+          char_metric->lbearing = -gm.gmptGlyphOrigin.x;
+          char_metric->rbearing = gm.gmBlackBoxX + gm.gmptGlyphOrigin.x;
+          char_metric->width = gm.gmCellIncX;
+          char_metric->ascent = -gm.gmptGlyphOrigin.y;
+          char_metric->descent = gm.gmBlackBoxY + gm.gmptGlyphOrigin.y;
+        }
+      else
+        char_metric->width = 0;
+    }
+}
+
 struct font_driver w32font_driver =
   {
     0, /* Qgdi */
@@ -1650,6 +1769,8 @@
 syms_of_w32font ()
 {
   DEFSYM (Qgdi, "gdi");
+  DEFSYM (Quniscribe, "uniscribe");
+  DEFSYM (QCformat, ":format");
 
   /* Generic font families.  */
   DEFSYM (Qmonospace, "monospace");