Prefer list1 (X) to Fcons (X, Qnil) when building lists.
[bpt/emacs.git] / src / w32uniscribe.c
index f6347bb..c153c8f 100644 (file)
@@ -1,5 +1,5 @@
 /* Font backend for the Microsoft W32 Uniscribe API.
-   Copyright (C) 2008-2011 Free Software Foundation, Inc.
+   Copyright (C) 2008-2013 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"
@@ -231,7 +230,7 @@ uniscribe_shape (Lisp_Object 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)
@@ -320,7 +319,7 @@ uniscribe_shape (Lisp_Object lgstring)
            }
           if (SUCCEEDED (result))
            {
-             int j, from, to;
+             int j, from, to, adj_offset = 0;
 
              from = 0;
              to = from;
@@ -334,7 +333,7 @@ uniscribe_shape (Lisp_Object lgstring)
 
                  if (NILP (lglyph))
                    {
-                     lglyph = Fmake_vector (make_number (LGLYPH_SIZE), Qnil);
+                     lglyph = LGLYPH_NEW ();
                      LGSTRING_SET_GLYPH (lgstring, lglyph_index, lglyph);
                    }
                  /* Copy to a 32-bit data type to shut up the
@@ -364,6 +363,32 @@ uniscribe_shape (Lisp_Object 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
@@ -392,9 +417,11 @@ uniscribe_shape (Lisp_Object 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
                    {
@@ -402,18 +429,47 @@ uniscribe_shape (Lisp_Object 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));
+                     Lisp_Object vec = make_uninit_vector (3);
+
+                     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];
+                   }
                }
            }
        }
@@ -469,7 +525,7 @@ uniscribe_encode_char (struct font *font, int 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);
@@ -507,7 +563,7 @@ uniscribe_encode_char (struct font *font, int 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];
             }
@@ -581,7 +637,7 @@ add_opentype_font_name_to_list (ENUMLOGFONTEX *logical_font,
       && 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]
@@ -961,4 +1017,3 @@ syms_of_w32uniscribe (void)
 
   register_font_driver (&uniscribe_font_driver, NULL);
 }
-