]> code.delx.au - gnu-emacs/blobdiff - src/w32uniscribe.c
* custom.texi (Init Examples): Add example of changing load-path.
[gnu-emacs] / src / w32uniscribe.c
index 6682def4f1a47a547be88bb492a5396feca29e27..f865c1abfd08a230bedf3cab5f495b42d2ba7acc 100644 (file)
@@ -1,12 +1,12 @@
 /* Font backend for the Microsoft W32 Uniscribe API.
-   Copyright (C) 2008 Free Software Foundation, Inc.
+   Copyright (C) 2008, 2009 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -14,11 +14,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
-#ifdef USE_FONT_BACKEND
 
 #include <config.h>
 /* Override API version - Uniscribe is only available as standard since
@@ -37,6 +34,7 @@ Boston, MA 02110-1301, USA.  */
 #include "dispextern.h"
 #include "character.h"
 #include "charset.h"
+#include "composite.h"
 #include "fontset.h"
 #include "font.h"
 #include "w32font.h"
@@ -79,14 +77,18 @@ static Lisp_Object
 uniscribe_list (frame, font_spec)
      Lisp_Object frame, font_spec;
 {
-  return w32font_list_internal (frame, font_spec, 1);
+  Lisp_Object fonts = w32font_list_internal (frame, font_spec, 1);
+  font_add_log ("uniscribe-list", font_spec, fonts);
+  return fonts;
 }
 
 static Lisp_Object
 uniscribe_match (frame, font_spec)
      Lisp_Object frame, font_spec;
 {
-  return w32font_match_internal (frame, font_spec, 1);
+  Lisp_Object entity = w32font_match_internal (frame, font_spec, 1);
+  font_add_log ("uniscribe-match", font_spec, entity);
+  return entity;
 }
 
 static Lisp_Object
@@ -112,32 +114,36 @@ uniscribe_list_family (frame)
   return list;
 }
 
-static struct font *
+static Lisp_Object
 uniscribe_open (f, font_entity, pixel_size)
      FRAME_PTR f;
      Lisp_Object font_entity;
      int pixel_size;
 {
+  Lisp_Object font_object
+    = font_make_object (VECSIZE (struct uniscribe_font_info),
+                       font_entity, pixel_size);
   struct uniscribe_font_info *uniscribe_font
-    = xmalloc (sizeof (struct uniscribe_font_info));
+    = (struct uniscribe_font_info *) XFONT_OBJECT (font_object);
 
-  if (uniscribe_font == NULL)
-    return NULL;
+  ASET (font_object, FONT_TYPE_INDEX, Quniscribe);
 
-  if (!w32font_open_internal (f, font_entity, pixel_size,
-                              (struct w32font_info *) uniscribe_font))
+  if (!w32font_open_internal (f, font_entity, pixel_size, font_object))
     {
-      xfree (uniscribe_font);
-      return NULL;
+      return Qnil;
     }
 
   /* Initialize the cache for this font.  */
   uniscribe_font->cache = NULL;
+
+  /* Uniscribe backend uses glyph indices.  */
+  uniscribe_font->w32_font.glyph_idx = ETO_GLYPH_INDEX;
+
   /* Mark the format as opentype  */
-  uniscribe_font->w32_font.font.format = Qopentype;
+  uniscribe_font->w32_font.font.props[FONT_FORMAT_INDEX] = Qopentype;
   uniscribe_font->w32_font.font.driver = &uniscribe_font_driver;
 
-  return (struct font *) uniscribe_font;
+  return font_object;
 }
 
 static void
@@ -149,7 +155,7 @@ uniscribe_close (f, font)
     = (struct uniscribe_font_info *) font;
 
   if (uniscribe_font->cache)
-    ScriptFreeCache (&uniscribe_font->cache);
+    ScriptFreeCache (&(uniscribe_font->cache));
 
   w32font_close (f, font);
 }
@@ -168,8 +174,7 @@ uniscribe_otf_capability (font)
 
   f = XFRAME (selected_frame);
   context = get_frame_dc (f);
-  old_font = SelectObject (context,
-                          ((W32FontStruct *) (font->font.font))->hfont);
+  old_font = SelectObject (context, FONT_HANDLE(font));
 
   features = otf_features (context, "GSUB");
   XSETCAR (capability, features);
@@ -206,22 +211,20 @@ uniscribe_shape (lgstring)
   wchar_t *chars;
   WORD *glyphs, *clusters;
   SCRIPT_ITEM *items;
-  SCRIPT_CONTROL control;
   SCRIPT_VISATTR *attributes;
   int *advances;
   GOFFSET *offsets;
   ABC overall_metrics;
-  MAT2 transform;
-  HDC context;
-  HFONT old_font;
   HRESULT result;
-  struct frame * f;
+  struct frame * f = NULL;
+  HDC context = NULL;
+  HFONT old_font = NULL;
 
   CHECK_FONT_GET_OBJECT (LGSTRING_FONT (lgstring), font);
   uniscribe_font = (struct uniscribe_font_info *) font;
 
   /* Get the chars from lgstring in a form we can use with uniscribe.  */
-  max_glyphs = nchars = LGSTRING_LENGTH (lgstring);
+  max_glyphs = nchars = LGSTRING_GLYPH_LEN (lgstring);
   done_glyphs = 0;
   chars = (wchar_t *) alloca (nchars * sizeof (wchar_t));
   for (i = 0; i < nchars; i++)
@@ -239,9 +242,8 @@ uniscribe_shape (lgstring)
      can be treated together.  First try a single run.  */
   max_items = 2;
   items = (SCRIPT_ITEM *) xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
-  bzero (&control, sizeof (control));
 
-  while ((result = ScriptItemize (chars, nchars, max_items, &control, NULL,
+  while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL,
                                  items, &nitems)) == E_OUTOFMEMORY)
     {
       /* If that wasn't enough, keep trying with one more run.  */
@@ -250,8 +252,7 @@ uniscribe_shape (lgstring)
                                        sizeof (SCRIPT_ITEM) * max_items + 1);
     }
 
-  /* 0 = success in Microsoft's backwards world.  */
-  if (result)
+  if (FAILED (result))
     {
       xfree (items);
       return Qnil;
@@ -260,36 +261,46 @@ uniscribe_shape (lgstring)
   /* TODO: When we get BIDI support, we need to call ScriptLayout here.
      Requires that we know the surrounding context.  */
 
-  f = XFRAME (selected_frame);
-  context = get_frame_dc (f);
-  old_font = SelectObject (context,
-                          ((W32FontStruct *) (font->font.font))->hfont);
-
   glyphs = alloca (max_glyphs * sizeof (WORD));
   clusters = alloca (nchars * sizeof (WORD));
   attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR));
   advances = alloca (max_glyphs * sizeof (int));
   offsets = alloca (max_glyphs * sizeof (GOFFSET));
-  bzero (&transform, sizeof (transform));
-  transform.eM11.value = 1;
-  transform.eM22.value = 1;
 
   for (i = 0; i < nitems; i++)
     {
       int nglyphs, nchars_in_run, rtl = items[i].a.fRTL ? -1 : 1;
       nchars_in_run = items[i+1].iCharPos - items[i].iCharPos;
 
+      /* Context may be NULL here, in which case the cache should be
+         used without needing to select the font.  */
       result = ScriptShape (context, &(uniscribe_font->cache),
                            chars + items[i].iCharPos, nchars_in_run,
                            max_glyphs - done_glyphs, &(items[i].a),
                            glyphs, clusters, attributes, &nglyphs);
+
+      if (result == E_PENDING && !context)
+       {
+         /* This assumes the selected frame is on the same display as the
+            one we are drawing.  It would be better for the frame to be
+            passed in.  */
+         f = XFRAME (selected_frame);
+         context = get_frame_dc (f);
+         old_font = SelectObject (context, FONT_HANDLE(font));
+
+         result = ScriptShape (context, &(uniscribe_font->cache),
+                               chars + items[i].iCharPos, nchars_in_run,
+                               max_glyphs - done_glyphs, &(items[i].a),
+                               glyphs, clusters, attributes, &nglyphs);
+       }
+
       if (result == E_OUTOFMEMORY)
        {
          /* Need a bigger lgstring.  */
          lgstring = Qnil;
          break;
        }
-      else if (result) /* Failure.  */
+      else if (FAILED (result))
        {
          /* Can't shape this run - return results so far if any.  */
          break;
@@ -305,7 +316,18 @@ uniscribe_shape (lgstring)
          result = ScriptPlace (context, &(uniscribe_font->cache),
                                glyphs, nglyphs, attributes, &(items[i].a),
                                advances, offsets, &overall_metrics);
-         if (result == 0) /* Success.  */
+         if (result == E_PENDING && !context)
+           {
+             /* Cache not complete...  */
+             f = XFRAME (selected_frame);
+             context = get_frame_dc (f);
+             old_font = SelectObject (context, FONT_HANDLE(font));
+
+             result = ScriptPlace (context, &(uniscribe_font->cache),
+                                   glyphs, nglyphs, attributes, &(items[i].a),
+                                   advances, offsets, &overall_metrics);
+           }
+          if (SUCCEEDED (result))
            {
              int j, nclusters, from, to;
 
@@ -317,13 +339,18 @@ uniscribe_shape (lgstring)
                  int lglyph_index = j + done_glyphs;
                  Lisp_Object lglyph = LGSTRING_GLYPH (lgstring, lglyph_index);
                  ABC char_metric;
+                 unsigned gl;
 
                  if (NILP (lglyph))
                    {
                      lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
                      LGSTRING_SET_GLYPH (lgstring, lglyph_index, lglyph);
                    }
-                 LGLYPH_SET_CODE (lglyph, glyphs[j]);
+                 /* Copy to a 32-bit data type to shut up the
+                    compiler warning in LGLYPH_SET_CODE about
+                    comparison being always false.  */
+                 gl = glyphs[j];
+                 LGLYPH_SET_CODE (lglyph, gl);
 
                  /* Detect clusters, for linking codes back to characters.  */
                  if (attributes[j].fClusterStart)
@@ -364,8 +391,18 @@ uniscribe_shape (lgstring)
                  result = ScriptGetGlyphABCWidth (context,
                                                   &(uniscribe_font->cache),
                                                   glyphs[j], &char_metric);
+                 if (result == E_PENDING && !context)
+                   {
+                     /* Cache incomplete... */
+                     f = XFRAME (selected_frame);
+                     context = get_frame_dc (f);
+                     old_font = SelectObject (context, FONT_HANDLE(font));
+                     result = ScriptGetGlyphABCWidth (context,
+                                                      &(uniscribe_font->cache),
+                                                      glyphs[j], &char_metric);
+                   }
 
-                 if (result == 0) /* Success.  */
+                 if (SUCCEEDED (result))
                    {
                      LGLYPH_SET_LBEARING (lglyph, char_metric.abcA);
                      LGLYPH_SET_RBEARING (lglyph, (char_metric.abcA
@@ -389,14 +426,19 @@ uniscribe_shape (lgstring)
                    }
                  else
                    LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
-               }           }
+               }
+           }
        }
       done_glyphs += nglyphs;
     }
 
   xfree (items);
-  SelectObject (context, old_font);
-  release_frame_dc (f, context);
+
+  if (context)
+    {
+      SelectObject (context, old_font);
+      release_frame_dc (f, context);
+    }
 
   if (NILP (lgstring))
     return Qnil;
@@ -412,35 +454,93 @@ uniscribe_encode_char (font, c)
      struct font *font;
      int c;
 {
-  wchar_t chars[1];
-  WORD indices[1];
-  HDC context;
-  struct frame *f;
-  HFONT old_font;
-  DWORD retval;
-
-  /* TODO: surrogates.  */
-  if (c > 0xFFFF)
-    return FONT_INVALID_CODE;
-
-  chars[0] = (wchar_t) c;
+  HDC context = NULL;
+  struct frame *f = NULL;
+  HFONT old_font = NULL;
+  unsigned code = FONT_INVALID_CODE;
+  wchar_t ch[2];
+  int len;
+  SCRIPT_ITEM* items;
+  int nitems;
+  struct uniscribe_font_info *uniscribe_font
+    = (struct uniscribe_font_info *)font;
 
-  /* Use selected frame until API is updated to pass the frame.  */
-  f = XFRAME (selected_frame);
-  context = get_frame_dc (f);
-  old_font = SelectObject (context,
-                           ((W32FontStruct *)(font->font.font))->hfont);
+  if (c < 0x10000)
+    {
+      ch[0] = (wchar_t) c;
+      len = 1;
+    }
+  else
+    {
+      DWORD surrogate = c - 0x10000;
 
-  retval = GetGlyphIndicesW (context, chars, 1, indices,
-                            GGI_MARK_NONEXISTING_GLYPHS);
+      /* High surrogate: U+D800 - U+DBFF.  */
+      ch[0] = 0xD800 + ((surrogate >> 10) & 0x03FF);
+      /* Low surrogate: U+DC00 - U+DFFF.  */
+      ch[1] = 0xDC00 + (surrogate & 0x03FF);
+      len = 2;
+    }
 
-  SelectObject (context, old_font);
-  release_frame_dc (f, context);
+  /* Non BMP characters must be handled by the uniscribe shaping
+     engine as GDI functions (except blindly displaying lines of
+     unicode text) and the promising looking ScriptGetCMap do not
+     convert surrogate pairs to glyph indexes correctly.  */
+    {
+      items = (SCRIPT_ITEM *) alloca (sizeof (SCRIPT_ITEM) * 2 + 1);
+      if (SUCCEEDED (ScriptItemize (ch, len, 2, NULL, NULL, items, &nitems)))
+       {
+         HRESULT result;
+          /* Surrogates seem to need 2 here, even though only one glyph is
+            returned.  Indic characters can also produce 2 or more glyphs for
+            a single code point, but they need to use uniscribe_shape
+            above for correct display.  */
+          WORD glyphs[2], clusters[2];
+          SCRIPT_VISATTR attrs[2];
+          int nglyphs;
+
+          result = ScriptShape (context, &(uniscribe_font->cache),
+                                ch, len, 2, &(items[0].a),
+                                glyphs, clusters, attrs, &nglyphs);
+
+          if (result == E_PENDING)
+            {
+              /* Use selected frame until API is updated to pass
+                 the frame.  */
+              f = XFRAME (selected_frame);
+              context = get_frame_dc (f);
+              old_font = SelectObject (context, FONT_HANDLE(font));
+              result = ScriptShape (context, &(uniscribe_font->cache),
+                                    ch, len, 2, &(items[0].a),
+                                    glyphs, clusters, attrs, &nglyphs);
+            }
+
+          if (SUCCEEDED (result) && nglyphs == 1)
+            {
+             /* Some fonts return .notdef glyphs instead of failing.
+                (Truetype spec reserves glyph code 0 for .notdef)  */
+             if (glyphs[0])
+               code = glyphs[0];
+            }
+          else if (SUCCEEDED (result) || result == E_OUTOFMEMORY)
+            {
+              /* This character produces zero or more than one glyph
+                 when shaped. But we still need the return from here
+                 to be valid for the shaping engine to be invoked
+                 later.  */
+              result = ScriptGetCMap (context, &(uniscribe_font->cache),
+                                      ch, len, 0, glyphs);
+              if (SUCCEEDED (result) && glyphs[0])
+                code = glyphs[0];
+            }
+       }
+    }
+    if (context)
+      {
+       SelectObject (context, old_font);
+       release_frame_dc (f, context);
+      }
 
-  if (retval == 1)
-    return indices[0] == 0xFFFF ? FONT_INVALID_CODE : indices[0];
-  else
-    return FONT_INVALID_CODE;
+    return code;
 }
 
 /*
@@ -494,8 +594,14 @@ add_opentype_font_name_to_list (logical_font, physical_font, font_type,
       && font_type != TRUETYPE_FONTTYPE)
     return 1;
 
-  family = intern_downcase (logical_font->elfLogFont.lfFaceName,
-                            strlen (logical_font->elfLogFont.lfFaceName));
+  /* Skip fonts that have no unicode coverage.  */
+  if (!physical_font->ntmFontSig.fsUsb[3]
+      && !physical_font->ntmFontSig.fsUsb[2]
+      && !physical_font->ntmFontSig.fsUsb[1]
+      && !(physical_font->ntmFontSig.fsUsb[0] & 0x3fffffff))
+    return 1;
+
+  family = intern_font_name (logical_font->elfLogFont.lfFaceName);
   if (! memq_no_quit (family, *list))
     *list = Fcons (family, *list);
 
@@ -630,10 +736,12 @@ int uniscribe_check_otf (font, otf_spec)
              OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
              break;
            }
+#if 0    /* Causes false positives.  */
          /* If there is a DFLT script defined in the font, use it
             if the specified script is not found.  */
          else if (script_id == default_script)
            OTF_INT16_VAL (tbl, scriptlist_table + 6 + j * 6, &script_table);
+#endif
        }
       /* If no specific or default script table was found, then this font
         does not support the script.  */
@@ -819,6 +927,7 @@ font_table_error:
 struct font_driver uniscribe_font_driver =
   {
     0, /* Quniscribe */
+    0, /* case insensitive */
     w32font_get_cache,
     uniscribe_list,
     uniscribe_match,
@@ -866,7 +975,5 @@ syms_of_w32uniscribe ()
   register_font_driver (&uniscribe_font_driver, NULL);
 }
 
-#endif /* USE_FONT_BACKEND  */
-
 /* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0
    (do not change this comment) */