]> code.delx.au - gnu-emacs/blobdiff - src/w32uniscribe.c
Avoid shadowing a global variable by a local one in frame.c.
[gnu-emacs] / src / w32uniscribe.c
index 94e4d5f05bd126775d580b709d650c39f1c32933..5d160b9d42f22dad437e8010a485c4d37370784c 100644 (file)
@@ -1,5 +1,5 @@
 /* Font backend for the Microsoft W32 Uniscribe API.
-   Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
+   Copyright (C) 2008-2012 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -27,7 +27,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define _WIN32_WINNT 0x500
 #include <windows.h>
 #include <usp10.h>
-#include <setjmp.h>
 
 #include "lisp.h"
 #include "w32term.h"
@@ -52,20 +51,15 @@ int uniscribe_available = 0;
 extern Lisp_Object Quniscribe;
 extern Lisp_Object Qopentype;
 
-extern int initialized;
-
-extern struct font_driver uniscribe_font_driver;
-
 /* EnumFontFamiliesEx callback.  */
-static int CALLBACK add_opentype_font_name_to_list P_ ((ENUMLOGFONTEX *,
-                                                        NEWTEXTMETRICEX *,
-                                                        DWORD, LPARAM));
+static int CALLBACK add_opentype_font_name_to_list (ENUMLOGFONTEX *,
+                                                    NEWTEXTMETRICEX *,
+                                                    DWORD, LPARAM);
 /* Used by uniscribe_otf_capability.  */
 static Lisp_Object otf_features (HDC context, char *table);
 
 static int
-memq_no_quit (elt, list)
-     Lisp_Object elt, list;
+memq_no_quit (Lisp_Object elt, Lisp_Object list)
 {
   while (CONSP (list) && ! EQ (XCAR (list), elt))
     list = XCDR (list);
@@ -75,8 +69,7 @@ memq_no_quit (elt, list)
 \f
 /* Font backend interface implementation.  */
 static Lisp_Object
-uniscribe_list (frame, font_spec)
-     Lisp_Object frame, font_spec;
+uniscribe_list (Lisp_Object frame, Lisp_Object font_spec)
 {
   Lisp_Object fonts = w32font_list_internal (frame, font_spec, 1);
   FONT_ADD_LOG ("uniscribe-list", font_spec, fonts);
@@ -84,8 +77,7 @@ uniscribe_list (frame, font_spec)
 }
 
 static Lisp_Object
-uniscribe_match (frame, font_spec)
-     Lisp_Object frame, font_spec;
+uniscribe_match (Lisp_Object frame, Lisp_Object font_spec)
 {
   Lisp_Object entity = w32font_match_internal (frame, font_spec, 1);
   FONT_ADD_LOG ("uniscribe-match", font_spec, entity);
@@ -93,15 +85,14 @@ uniscribe_match (frame, font_spec)
 }
 
 static Lisp_Object
-uniscribe_list_family (frame)
-     Lisp_Object frame;
+uniscribe_list_family (Lisp_Object frame)
 {
   Lisp_Object list = Qnil;
   LOGFONT font_match_pattern;
   HDC dc;
   FRAME_PTR f = XFRAME (frame);
 
-  bzero (&font_match_pattern, sizeof (font_match_pattern));
+  memset (&font_match_pattern, 0, sizeof (font_match_pattern));
   /* Limit enumerated fonts to outline fonts to save time.  */
   font_match_pattern.lfOutPrecision = OUT_OUTLINE_PRECIS;
 
@@ -116,10 +107,7 @@ uniscribe_list_family (frame)
 }
 
 static Lisp_Object
-uniscribe_open (f, font_entity, pixel_size)
-     FRAME_PTR f;
-     Lisp_Object font_entity;
-     int pixel_size;
+uniscribe_open (FRAME_PTR f, Lisp_Object font_entity, int pixel_size)
 {
   Lisp_Object font_object
     = font_make_object (VECSIZE (struct uniscribe_font_info),
@@ -148,9 +136,7 @@ uniscribe_open (f, font_entity, pixel_size)
 }
 
 static void
-uniscribe_close (f, font)
-     FRAME_PTR f;
-     struct font *font;
+uniscribe_close (FRAME_PTR f, struct font *font)
 {
   struct uniscribe_font_info *uniscribe_font
     = (struct uniscribe_font_info *) font;
@@ -164,8 +150,7 @@ uniscribe_close (f, font)
 /* Return a list describing which scripts/languages FONT supports by
    which GSUB/GPOS features of OpenType tables.  */
 static Lisp_Object
-uniscribe_otf_capability (font)
-     struct font *font;
+uniscribe_otf_capability (struct font *font)
 {
   HDC context;
   HFONT old_font;
@@ -190,20 +175,20 @@ uniscribe_otf_capability (font)
 
 /* Uniscribe implementation of shape for font backend.
 
-   Shape text in LGSTRING.  See the docstring of `font-make-gstring'
-   for the format of LGSTRING.  If the (N+1)th element of LGSTRING
-   is nil, input of shaping is from the 1st to (N)th elements.  In
-   each input glyph, FROM, TO, CHAR, and CODE are already set.
+   Shape text in LGSTRING.  See the docstring of
+   `composition-get-gstring' for the format of LGSTRING.  If the
+   (N+1)th element of LGSTRING is nil, input of shaping is from the
+   1st to (N)th elements.  In each input glyph, FROM, TO, CHAR, and
+   CODE are already set.
 
    This function updates all fields of the input glyphs.  If the
    output glyphs (M) are more than the input glyphs (N), (N+1)th
    through (M)th elements of LGSTRING are updated possibly by making
    a new glyph object and storing it in LGSTRING.  If (M) is greater
-   than the length of LGSTRING, nil should be return.  In that case,
-   this function is called again with the larger LGSTRING.  */
+   than the length of LGSTRING, nil should be returned.  In that case,
+   this function is called again with a larger LGSTRING.  */
 static Lisp_Object
-uniscribe_shape (lgstring)
-     Lisp_Object lgstring;
+uniscribe_shape (Lisp_Object lgstring)
 {
   struct font * font;
   struct uniscribe_font_info * uniscribe_font;
@@ -228,6 +213,9 @@ uniscribe_shape (lgstring)
   max_glyphs = nchars = LGSTRING_GLYPH_LEN (lgstring);
   done_glyphs = 0;
   chars = (wchar_t *) alloca (nchars * sizeof (wchar_t));
+  /* FIXME: This loop assumes that characters in the input LGSTRING
+     are all inside the BMP.  Need to encode characters beyond the BMP
+     as UTF-16.  */
   for (i = 0; i < nchars; i++)
     {
       /* lgstring can be bigger than the number of characters in it, in
@@ -242,7 +230,7 @@ uniscribe_shape (lgstring)
   /* First we need to break up the glyph string into runs of glyphs that
      can be treated together.  First try a single run.  */
   max_items = 2;
-  items = (SCRIPT_ITEM *) xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
+  items = xmalloc (sizeof (SCRIPT_ITEM) * max_items + 1);
 
   while ((result = ScriptItemize (chars, nchars, max_items, NULL, NULL,
                                  items, &nitems)) == E_OUTOFMEMORY)
@@ -259,9 +247,6 @@ uniscribe_shape (lgstring)
       return Qnil;
     }
 
-  /* TODO: When we get BIDI support, we need to call ScriptLayout here.
-     Requires that we know the surrounding context.  */
-
   glyphs = alloca (max_glyphs * sizeof (WORD));
   clusters = alloca (nchars * sizeof (WORD));
   attributes = alloca (max_glyphs * sizeof (SCRIPT_VISATTR));
@@ -270,8 +255,12 @@ uniscribe_shape (lgstring)
 
   for (i = 0; i < nitems; i++)
     {
-      int nglyphs, nchars_in_run, rtl = items[i].a.fRTL ? -1 : 1;
+      int nglyphs, nchars_in_run;
       nchars_in_run = items[i+1].iCharPos - items[i].iCharPos;
+      /* Force ScriptShape to generate glyphs in the same order as
+        they are in the input LGSTRING, which is in the logical
+        order.  */
+      items[i].a.fLogicalOrder = 1;
 
       /* Context may be NULL here, in which case the cache should be
          used without needing to select the font.  */
@@ -330,9 +319,9 @@ uniscribe_shape (lgstring)
            }
           if (SUCCEEDED (result))
            {
-             int j, nclusters, from, to;
+             int j, from, to, adj_offset = 0;
 
-             from = rtl > 0 ? 0 : nchars_in_run - 1;
+             from = 0;
              to = from;
 
              for (j = 0; j < nglyphs; j++)
@@ -353,22 +342,19 @@ uniscribe_shape (lgstring)
                  gl = glyphs[j];
                  LGLYPH_SET_CODE (lglyph, gl);
 
-                 /* Detect clusters, for linking codes back to characters.  */
+                 /* Detect clusters, for linking codes back to
+                    characters.  */
                  if (attributes[j].fClusterStart)
                    {
-                     while (from >= 0 && from < nchars_in_run
-                            && clusters[from] < j)
-                       from += rtl;
-                     if (from < 0)
-                       from = to = 0;
-                     else if (from >= nchars_in_run)
+                     while (from < nchars_in_run && clusters[from] < j)
+                       from++;
+                     if (from >= nchars_in_run)
                        from = to = nchars_in_run - 1;
                      else
                        {
                          int k;
-                         to = rtl > 0 ? nchars_in_run - 1 : 0;
-                         for (k = from + rtl; k >= 0 && k < nchars_in_run;
-                              k += rtl)
+                         to = nchars_in_run - 1;
+                         for (k = from + 1; k < nchars_in_run; k++)
                            {
                              if (clusters[k] > j)
                                {
@@ -377,6 +363,32 @@ uniscribe_shape (lgstring)
                                }
                            }
                        }
+
+                     /* For RTL text, the Uniscribe shaper prepares
+                        the values in ADVANCES array for layout in
+                        reverse order, whereby "advance width" is
+                        applied to move the pen in reverse direction
+                        and _before_ drawing the glyph.  Since we
+                        draw glyphs in their normal left-to-right
+                        order, we need to adjust the coordinates of
+                        each non-base glyph in a grapheme cluster via
+                        X-OFF component of the gstring's ADJUSTMENT
+                        sub-vector.  This loop computes, for each
+                        grapheme cluster, the initial value of the
+                        adjustment for the base character, which is
+                        then updated for each successive glyph in the
+                        grapheme cluster.  */
+                     if (items[i].a.fRTL)
+                       {
+                         int j1 = j;
+
+                         adj_offset = 0;
+                         while (j1 < nglyphs && !attributes[j1].fClusterStart)
+                           {
+                             adj_offset += advances[j1];
+                             j1++;
+                           }
+                       }
                    }
 
                  LGLYPH_SET_CHAR (lglyph, chars[items[i].iCharPos
@@ -405,9 +417,11 @@ uniscribe_shape (lgstring)
 
                  if (SUCCEEDED (result))
                    {
-                     LGLYPH_SET_LBEARING (lglyph, char_metric.abcA);
-                     LGLYPH_SET_RBEARING (lglyph, (char_metric.abcA
-                                                   + char_metric.abcB));
+                     int lbearing = char_metric.abcA;
+                     int rbearing = char_metric.abcA + char_metric.abcB;
+
+                     LGLYPH_SET_LBEARING (lglyph, lbearing);
+                     LGLYPH_SET_RBEARING (lglyph, rbearing);
                    }
                  else
                    {
@@ -415,18 +429,47 @@ uniscribe_shape (lgstring)
                      LGLYPH_SET_RBEARING (lglyph, advances[j]);
                    }
 
-                 if (offsets[j].du || offsets[j].dv)
+                 if (offsets[j].du || offsets[j].dv
+                     /* For non-base glyphs of RTL grapheme clusters,
+                        adjust the X offset even if both DU and DV
+                        are zero.  */
+                     || (!attributes[j].fClusterStart && items[i].a.fRTL))
                    {
                      Lisp_Object vec;
                      vec = Fmake_vector (make_number (3), Qnil);
-                     ASET (vec, 0, make_number (offsets[j].du));
-                     ASET (vec, 1, make_number (offsets[j].dv));
+                     if (items[i].a.fRTL)
+                       {
+                         /* Empirically, it looks like Uniscribe
+                            interprets DU in reverse direction for
+                            RTL clusters.  E.g., if we don't reverse
+                            the direction, the Hebrew point HOLAM is
+                            drawn above the right edge of the base
+                            consonant, instead of above the left edge.  */
+                         ASET (vec, 0, make_number (-offsets[j].du
+                                                    + adj_offset));
+                         /* Update the adjustment value for the width
+                            advance of the glyph we just emitted.  */
+                         adj_offset -= 2 * advances[j];
+                       }
+                     else
+                       ASET (vec, 0, make_number (offsets[j].du + adj_offset));
+                     /* In the font definition coordinate system, the
+                        Y coordinate points up, while in our screen
+                        coordinates Y grows downwards.  So we need to
+                        reverse the sign of Y-OFFSET here.  */
+                     ASET (vec, 1, make_number (-offsets[j].dv));
                      /* Based on what ftfont.c does... */
                      ASET (vec, 2, make_number (advances[j]));
                      LGLYPH_SET_ADJUSTMENT (lglyph, vec);
                    }
                  else
-                   LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
+                   {
+                     LGLYPH_SET_ADJUSTMENT (lglyph, Qnil);
+                     /* Update the adjustment value to compensate for
+                        the width of the base character.  */
+                     if (items[i].a.fRTL)
+                       adj_offset -= advances[j];
+                   }
                }
            }
        }
@@ -451,9 +494,7 @@ uniscribe_shape (lgstring)
    Return a glyph code of FONT for character C (Unicode code point).
    If FONT doesn't have such a glyph, return FONT_INVALID_CODE.  */
 static unsigned
-uniscribe_encode_char (font, c)
-     struct font *font;
-     int c;
+uniscribe_encode_char (struct font *font, int c)
 {
   HDC context = NULL;
   struct frame *f = NULL;
@@ -484,7 +525,7 @@ uniscribe_encode_char (font, c)
 
   /* 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
+     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);
@@ -499,6 +540,10 @@ uniscribe_encode_char (font, c)
           SCRIPT_VISATTR attrs[2];
           int nglyphs;
 
+         /* Force ScriptShape to generate glyphs in the logical
+            order.  */
+         items[0].a.fLogicalOrder = 1;
+
           result = ScriptShape (context, &(uniscribe_font->cache),
                                 ch, len, 2, &(items[0].a),
                                 glyphs, clusters, attrs, &nglyphs);
@@ -518,7 +563,7 @@ uniscribe_encode_char (font, c)
           if (SUCCEEDED (result) && nglyphs == 1)
             {
              /* Some fonts return .notdef glyphs instead of failing.
-                (Truetype spec reserves glyph code 0 for .notdef)  */
+                (TrueType spec reserves glyph code 0 for .notdef)  */
              if (glyphs[0])
                code = glyphs[0];
             }
@@ -574,12 +619,9 @@ uniscribe_encode_char (font, c)
    Adds the name of opentype fonts to a Lisp list (passed in as the
    lParam arg). */
 static int CALLBACK
-add_opentype_font_name_to_list (logical_font, physical_font, font_type,
-                                list_object)
-     ENUMLOGFONTEX *logical_font;
-     NEWTEXTMETRICEX *physical_font;
-     DWORD font_type;
-     LPARAM list_object;
+add_opentype_font_name_to_list (ENUMLOGFONTEX *logical_font,
+                               NEWTEXTMETRICEX *physical_font,
+                               DWORD font_type, LPARAM list_object)
 {
   Lisp_Object* list = (Lisp_Object *) list_object;
   Lisp_Object family;
@@ -595,7 +637,7 @@ add_opentype_font_name_to_list (logical_font, physical_font, font_type,
       && font_type != TRUETYPE_FONTTYPE)
     return 1;
 
-  /* Skip fonts that have no unicode coverage.  */
+  /* Skip fonts that have no Unicode coverage.  */
   if (!physical_font->ntmFontSig.fsUsb[3]
       && !physical_font->ntmFontSig.fsUsb[2]
       && !physical_font->ntmFontSig.fsUsb[1]
@@ -643,17 +685,13 @@ add_opentype_font_name_to_list (logical_font, physical_font, font_type,
     STR[4] = '\0';                                           \
   } while (0)
 
-static char* NOTHING = "    ";
-
 #define SNAME(VAL) SDATA (SYMBOL_NAME (VAL))
 
 /* Check if font supports the otf script/language/features specified.
    OTF_SPEC is in the format
      (script lang [(gsub_feature ...)|nil] [(gpos_feature ...)]?) */
 int
-uniscribe_check_otf (font, otf_spec)
-     LOGFONT *font;
-     Lisp_Object otf_spec;
+uniscribe_check_otf (LOGFONT *font, Lisp_Object otf_spec)
 {
   Lisp_Object script, lang, rest;
   Lisp_Object features[2];
@@ -662,7 +700,6 @@ uniscribe_check_otf (font, otf_spec)
   struct frame * f;
   HDC context;
   HFONT check_font, old_font;
-  DWORD table;
   int i, retval = 0;
   struct gcpro gcpro1;
 
@@ -952,13 +989,17 @@ struct font_driver uniscribe_font_driver =
     NULL, /* otf_drive - use shape instead.  */
     NULL, /* start_for_frame */
     NULL, /* end_for_frame */
-    uniscribe_shape
+    uniscribe_shape,
+    NULL, /* check */
+    NULL, /* get_variation_glyphs */
+    NULL, /* filter_properties */
+    NULL, /* cached_font_ok */
   };
 
 /* Note that this should be called at every startup, not just when dumping,
    as it needs to test for the existence of the Uniscribe library.  */
 void
-syms_of_w32uniscribe ()
+syms_of_w32uniscribe (void)
 {
   HMODULE uniscribe;
 
@@ -976,6 +1017,3 @@ syms_of_w32uniscribe ()
 
   register_font_driver (&uniscribe_font_driver, NULL);
 }
-
-/* arch-tag: 9530f0e1-7471-47dd-a780-94330af87ea0
-   (do not change this comment) */