Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright  2011,2012,2013  Google, Inc.
      3  *
      4  *  This is part of HarfBuzz, a text shaping library.
      5  *
      6  * Permission is hereby granted, without written agreement and without
      7  * license or royalty fees, to use, copy, modify, and distribute this
      8  * software and its documentation for any purpose, provided that the
      9  * above copyright notice and the following two paragraphs appear in
     10  * all copies of this software.
     11  *
     12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     16  * DAMAGE.
     17  *
     18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     23  *
     24  * Google Author(s): Behdad Esfahbod
     25  */
     26 
     27 #define HB_SHAPER uniscribe
     28 #include "hb-shaper-impl-private.hh"
     29 
     30 #include <windows.h>
     31 #include <usp10.h>
     32 #include <rpc.h>
     33 
     34 #include "hb-uniscribe.h"
     35 
     36 #include "hb-open-file-private.hh"
     37 #include "hb-ot-name-table.hh"
     38 #include "hb-ot-tag.h"
     39 
     40 
     41 #ifndef HB_DEBUG_UNISCRIBE
     42 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
     43 #endif
     44 
     45 
     46 typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
     47   const WCHAR *pwcInChars,
     48   int cInChars,
     49   int cMaxItems,
     50   const SCRIPT_CONTROL *psControl,
     51   const SCRIPT_STATE *psState,
     52   SCRIPT_ITEM *pItems,
     53   OPENTYPE_TAG *pScriptTags,
     54   int *pcItems
     55 );
     56 
     57 typedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/(
     58   HDC hdc,
     59   SCRIPT_CACHE *psc,
     60   SCRIPT_ANALYSIS *psa,
     61   OPENTYPE_TAG tagScript,
     62   OPENTYPE_TAG tagLangSys,
     63   int *rcRangeChars,
     64   TEXTRANGE_PROPERTIES **rpRangeProperties,
     65   int cRanges,
     66   const WCHAR *pwcChars,
     67   int cChars,
     68   int cMaxGlyphs,
     69   WORD *pwLogClust,
     70   SCRIPT_CHARPROP *pCharProps,
     71   WORD *pwOutGlyphs,
     72   SCRIPT_GLYPHPROP *pOutGlyphProps,
     73   int *pcGlyphs
     74 );
     75 
     76 typedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/(
     77   HDC hdc,
     78   SCRIPT_CACHE *psc,
     79   SCRIPT_ANALYSIS *psa,
     80   OPENTYPE_TAG tagScript,
     81   OPENTYPE_TAG tagLangSys,
     82   int *rcRangeChars,
     83   TEXTRANGE_PROPERTIES **rpRangeProperties,
     84   int cRanges,
     85   const WCHAR *pwcChars,
     86   WORD *pwLogClust,
     87   SCRIPT_CHARPROP *pCharProps,
     88   int cChars,
     89   const WORD *pwGlyphs,
     90   const SCRIPT_GLYPHPROP *pGlyphProps,
     91   int cGlyphs,
     92   int *piAdvance,
     93   GOFFSET *pGoffset,
     94   ABC *pABC
     95 );
     96 
     97 
     98 /* Fallback implementations. */
     99 
    100 static HRESULT WINAPI
    101 hb_ScriptItemizeOpenType(
    102   const WCHAR *pwcInChars,
    103   int cInChars,
    104   int cMaxItems,
    105   const SCRIPT_CONTROL *psControl,
    106   const SCRIPT_STATE *psState,
    107   SCRIPT_ITEM *pItems,
    108   OPENTYPE_TAG *pScriptTags,
    109   int *pcItems
    110 )
    111 {
    112 {
    113   return ScriptItemize (pwcInChars,
    114 			cInChars,
    115 			cMaxItems,
    116 			psControl,
    117 			psState,
    118 			pItems,
    119 			pcItems);
    120 }
    121 }
    122 
    123 static HRESULT WINAPI
    124 hb_ScriptShapeOpenType(
    125   HDC hdc,
    126   SCRIPT_CACHE *psc,
    127   SCRIPT_ANALYSIS *psa,
    128   OPENTYPE_TAG tagScript,
    129   OPENTYPE_TAG tagLangSys,
    130   int *rcRangeChars,
    131   TEXTRANGE_PROPERTIES **rpRangeProperties,
    132   int cRanges,
    133   const WCHAR *pwcChars,
    134   int cChars,
    135   int cMaxGlyphs,
    136   WORD *pwLogClust,
    137   SCRIPT_CHARPROP *pCharProps,
    138   WORD *pwOutGlyphs,
    139   SCRIPT_GLYPHPROP *pOutGlyphProps,
    140   int *pcGlyphs
    141 )
    142 {
    143   SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps;
    144   return ScriptShape (hdc,
    145 		      psc,
    146 		      pwcChars,
    147 		      cChars,
    148 		      cMaxGlyphs,
    149 		      psa,
    150 		      pwOutGlyphs,
    151 		      pwLogClust,
    152 		      psva,
    153 		      pcGlyphs);
    154 }
    155 
    156 static HRESULT WINAPI
    157 hb_ScriptPlaceOpenType(
    158   HDC hdc,
    159   SCRIPT_CACHE *psc,
    160   SCRIPT_ANALYSIS *psa,
    161   OPENTYPE_TAG tagScript,
    162   OPENTYPE_TAG tagLangSys,
    163   int *rcRangeChars,
    164   TEXTRANGE_PROPERTIES **rpRangeProperties,
    165   int cRanges,
    166   const WCHAR *pwcChars,
    167   WORD *pwLogClust,
    168   SCRIPT_CHARPROP *pCharProps,
    169   int cChars,
    170   const WORD *pwGlyphs,
    171   const SCRIPT_GLYPHPROP *pGlyphProps,
    172   int cGlyphs,
    173   int *piAdvance,
    174   GOFFSET *pGoffset,
    175   ABC *pABC
    176 )
    177 {
    178   SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pGlyphProps;
    179   return ScriptPlace (hdc,
    180 		      psc,
    181 		      pwGlyphs,
    182 		      cGlyphs,
    183 		      psva,
    184 		      psa,
    185 		      piAdvance,
    186 		      pGoffset,
    187 		      pABC);
    188 }
    189 
    190 
    191 struct hb_uniscribe_shaper_funcs_t {
    192   SIOT ScriptItemizeOpenType;
    193   SSOT ScriptShapeOpenType;
    194   SPOT ScriptPlaceOpenType;
    195 
    196   inline void init (void)
    197   {
    198     HMODULE hinstLib;
    199     this->ScriptItemizeOpenType = NULL;
    200     this->ScriptShapeOpenType   = NULL;
    201     this->ScriptPlaceOpenType   = NULL;
    202 
    203     hinstLib = GetModuleHandle (TEXT ("usp10.dll"));
    204     if (hinstLib)
    205     {
    206       this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType");
    207       this->ScriptShapeOpenType   = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType");
    208       this->ScriptPlaceOpenType   = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType");
    209     }
    210     if (!this->ScriptItemizeOpenType ||
    211 	!this->ScriptShapeOpenType   ||
    212 	!this->ScriptPlaceOpenType)
    213     {
    214       DEBUG_MSG (UNISCRIBE, NULL, "OpenType versions of functions not found; falling back.");
    215       this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType;
    216       this->ScriptShapeOpenType   = hb_ScriptShapeOpenType;
    217       this->ScriptPlaceOpenType   = hb_ScriptPlaceOpenType;
    218     }
    219   }
    220 };
    221 static hb_uniscribe_shaper_funcs_t *uniscribe_funcs;
    222 
    223 static inline void
    224 free_uniscribe_funcs (void)
    225 {
    226   free (uniscribe_funcs);
    227 }
    228 
    229 static hb_uniscribe_shaper_funcs_t *
    230 hb_uniscribe_shaper_get_funcs (void)
    231 {
    232 retry:
    233   hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs);
    234 
    235   if (unlikely (!funcs))
    236   {
    237     funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
    238     if (unlikely (!funcs))
    239       return NULL;
    240 
    241     funcs->init ();
    242 
    243     if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) {
    244       free (funcs);
    245       goto retry;
    246     }
    247 
    248 #ifdef HAVE_ATEXIT
    249     atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
    250 #endif
    251   }
    252 
    253   return funcs;
    254 }
    255 
    256 
    257 struct active_feature_t {
    258   OPENTYPE_FEATURE_RECORD rec;
    259   unsigned int order;
    260 
    261   static int cmp (const active_feature_t *a, const active_feature_t *b) {
    262     return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 :
    263 	   a->order < b->order ? -1 : a->order > b->order ? 1 :
    264 	   a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 :
    265 	   0;
    266   }
    267   bool operator== (const active_feature_t *f) {
    268     return cmp (this, f) == 0;
    269   }
    270 };
    271 
    272 struct feature_event_t {
    273   unsigned int index;
    274   bool start;
    275   active_feature_t feature;
    276 
    277   static int cmp (const feature_event_t *a, const feature_event_t *b) {
    278     return a->index < b->index ? -1 : a->index > b->index ? 1 :
    279 	   a->start < b->start ? -1 : a->start > b->start ? 1 :
    280 	   active_feature_t::cmp (&a->feature, &b->feature);
    281   }
    282 };
    283 
    284 struct range_record_t {
    285   TEXTRANGE_PROPERTIES props;
    286   unsigned int index_first; /* == start */
    287   unsigned int index_last;  /* == end - 1 */
    288 };
    289 
    290 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face)
    291 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font)
    292 
    293 
    294 /*
    295  * shaper face data
    296  */
    297 
    298 struct hb_uniscribe_shaper_face_data_t {
    299   HANDLE fh;
    300   hb_uniscribe_shaper_funcs_t *funcs;
    301   wchar_t face_name[LF_FACESIZE];
    302 };
    303 
    304 /* face_name should point to a wchar_t[LF_FACESIZE] object. */
    305 static void
    306 _hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen)
    307 {
    308   /* We'll create a private name for the font from a UUID using a simple,
    309    * somewhat base64-like encoding scheme */
    310   const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
    311   UUID id;
    312   UuidCreate ((UUID*) &id);
    313   unsigned int name_str_len = 0;
    314   face_name[name_str_len++] = 'F';
    315   face_name[name_str_len++] = '_';
    316   unsigned char *p = (unsigned char *) &id;
    317   for (unsigned int i = 0; i < 16; i += 2)
    318   {
    319     /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
    320      * using the bits in groups of 5,5,6 to select chars from enc.
    321      * This will generate 24 characters; with the 'F_' prefix we already provided,
    322      * the name will be 26 chars (plus the NUL terminator), so will always fit within
    323      * face_name (LF_FACESIZE = 32). */
    324     face_name[name_str_len++] = enc[p[i] >> 3];
    325     face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
    326     face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
    327   }
    328   face_name[name_str_len] = 0;
    329   if (plen)
    330     *plen = name_str_len;
    331 }
    332 
    333 /* Destroys blob. */
    334 static hb_blob_t *
    335 _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
    336 {
    337   /* Create a copy of the font data, with the 'name' table replaced by a
    338    * table that names the font with our private F_* name created above.
    339    * For simplicity, we just append a new 'name' table and update the
    340    * sfnt directory; the original table is left in place, but unused.
    341    *
    342    * The new table will contain just 5 name IDs: family, style, unique,
    343    * full, PS. All of them point to the same name data with our unique name.
    344    */
    345 
    346   blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
    347 
    348   unsigned int length, new_length, name_str_len;
    349   const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
    350 
    351   _hb_generate_unique_face_name (new_name, &name_str_len);
    352 
    353   static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
    354 
    355   unsigned int name_table_length = OT::name::min_size +
    356                                    ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size +
    357                                    name_str_len * 2; /* for name data in UTF16BE form */
    358   unsigned int name_table_offset = (length + 3) & ~3;
    359 
    360   new_length = name_table_offset + ((name_table_length + 3) & ~3);
    361   void *new_sfnt_data = calloc (1, new_length);
    362   if (!new_sfnt_data)
    363   {
    364     hb_blob_destroy (blob);
    365     return NULL;
    366   }
    367 
    368   memcpy(new_sfnt_data, orig_sfnt_data, length);
    369 
    370   OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
    371   name.format.set (0);
    372   name.count.set (ARRAY_LENGTH (name_IDs));
    373   name.stringOffset.set (name.get_size ());
    374   for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
    375   {
    376     OT::NameRecord &record = name.nameRecord[i];
    377     record.platformID.set (3);
    378     record.encodingID.set (1);
    379     record.languageID.set (0x0409u); /* English */
    380     record.nameID.set (name_IDs[i]);
    381     record.length.set (name_str_len * 2);
    382     record.offset.set (0);
    383   }
    384 
    385   /* Copy string data from new_name, converting wchar_t to UTF16BE. */
    386   unsigned char *p = &OT::StructAfter<unsigned char> (name);
    387   for (unsigned int i = 0; i < name_str_len; i++)
    388   {
    389     *p++ = new_name[i] >> 8;
    390     *p++ = new_name[i] & 0xff;
    391   }
    392 
    393   /* Adjust name table entry to point to new name table */
    394   const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data);
    395   unsigned int face_count = file.get_face_count ();
    396   for (unsigned int face_index = 0; face_index < face_count; face_index++)
    397   {
    398     /* Note: doing multiple edits (ie. TTC) can be unsafe.  There may be
    399      * toe-stepping.  But we don't really care. */
    400     const OT::OpenTypeFontFace &face = file.get_face (face_index);
    401     unsigned int index;
    402     if (face.find_table_index (HB_OT_TAG_name, &index))
    403     {
    404       OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
    405       record.checkSum.set_for_data (&name, name_table_length);
    406       record.offset.set (name_table_offset);
    407       record.length.set (name_table_length);
    408     }
    409     else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
    410     {
    411       free (new_sfnt_data);
    412       hb_blob_destroy (blob);
    413       return NULL;
    414     }
    415   }
    416 
    417   /* The checkSumAdjustment field in the 'head' table is now wrong,
    418    * but that doesn't actually seem to cause any problems so we don't
    419    * bother. */
    420 
    421   hb_blob_destroy (blob);
    422   return hb_blob_create ((const char *) new_sfnt_data, new_length,
    423 			 HB_MEMORY_MODE_WRITABLE, NULL, free);
    424 }
    425 
    426 hb_uniscribe_shaper_face_data_t *
    427 _hb_uniscribe_shaper_face_data_create (hb_face_t *face)
    428 {
    429   hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
    430   if (unlikely (!data))
    431     return NULL;
    432 
    433   data->funcs = hb_uniscribe_shaper_get_funcs ();
    434   if (unlikely (!data->funcs))
    435   {
    436     free (data);
    437     return NULL;
    438   }
    439 
    440   hb_blob_t *blob = hb_face_reference_blob (face);
    441   if (unlikely (!hb_blob_get_length (blob)))
    442     DEBUG_MSG (UNISCRIBE, face, "Face has empty blob");
    443 
    444   blob = _hb_rename_font (blob, data->face_name);
    445   if (unlikely (!blob))
    446   {
    447     free (data);
    448     return NULL;
    449   }
    450 
    451   DWORD num_fonts_installed;
    452   data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL),
    453 				   hb_blob_get_length (blob),
    454 				   0, &num_fonts_installed);
    455   if (unlikely (!data->fh))
    456   {
    457     DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
    458     free (data);
    459     return NULL;
    460   }
    461 
    462   return data;
    463 }
    464 
    465 void
    466 _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
    467 {
    468   RemoveFontMemResourceEx (data->fh);
    469   free (data);
    470 }
    471 
    472 
    473 /*
    474  * shaper font data
    475  */
    476 
    477 struct hb_uniscribe_shaper_font_data_t {
    478   HDC hdc;
    479   LOGFONTW log_font;
    480   HFONT hfont;
    481   SCRIPT_CACHE script_cache;
    482 };
    483 
    484 static bool
    485 populate_log_font (LOGFONTW  *lf,
    486 		   hb_font_t *font)
    487 {
    488   memset (lf, 0, sizeof (*lf));
    489   lf->lfHeight = -font->y_scale;
    490   lf->lfCharSet = DEFAULT_CHARSET;
    491 
    492   hb_face_t *face = font->face;
    493   hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    494 
    495   memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
    496 
    497   return true;
    498 }
    499 
    500 hb_uniscribe_shaper_font_data_t *
    501 _hb_uniscribe_shaper_font_data_create (hb_font_t *font)
    502 {
    503   if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL;
    504 
    505   hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
    506   if (unlikely (!data))
    507     return NULL;
    508 
    509   data->hdc = GetDC (NULL);
    510 
    511   if (unlikely (!populate_log_font (&data->log_font, font))) {
    512     DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
    513     _hb_uniscribe_shaper_font_data_destroy (data);
    514     return NULL;
    515   }
    516 
    517   data->hfont = CreateFontIndirectW (&data->log_font);
    518   if (unlikely (!data->hfont)) {
    519     DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
    520     _hb_uniscribe_shaper_font_data_destroy (data);
    521      return NULL;
    522   }
    523 
    524   if (!SelectObject (data->hdc, data->hfont)) {
    525     DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
    526     _hb_uniscribe_shaper_font_data_destroy (data);
    527      return NULL;
    528   }
    529 
    530   return data;
    531 }
    532 
    533 void
    534 _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
    535 {
    536   if (data->hdc)
    537     ReleaseDC (NULL, data->hdc);
    538   if (data->hfont)
    539     DeleteObject (data->hfont);
    540   if (data->script_cache)
    541     ScriptFreeCache (&data->script_cache);
    542   free (data);
    543 }
    544 
    545 LOGFONTW *
    546 hb_uniscribe_font_get_logfontw (hb_font_t *font)
    547 {
    548   if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
    549   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
    550   return &font_data->log_font;
    551 }
    552 
    553 HFONT
    554 hb_uniscribe_font_get_hfont (hb_font_t *font)
    555 {
    556   if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
    557   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
    558   return font_data->hfont;
    559 }
    560 
    561 
    562 /*
    563  * shaper shape_plan data
    564  */
    565 
    566 struct hb_uniscribe_shaper_shape_plan_data_t {};
    567 
    568 hb_uniscribe_shaper_shape_plan_data_t *
    569 _hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
    570 					     const hb_feature_t *user_features HB_UNUSED,
    571 					     unsigned int        num_user_features HB_UNUSED)
    572 {
    573   return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
    574 }
    575 
    576 void
    577 _hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
    578 {
    579 }
    580 
    581 
    582 /*
    583  * shaper
    584  */
    585 
    586 
    587 hb_bool_t
    588 _hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
    589 		     hb_font_t          *font,
    590 		     hb_buffer_t        *buffer,
    591 		     const hb_feature_t *features,
    592 		     unsigned int        num_features)
    593 {
    594   hb_face_t *face = font->face;
    595   hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    596   hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
    597   hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
    598 
    599   /*
    600    * Set up features.
    601    */
    602   hb_auto_array_t<OPENTYPE_FEATURE_RECORD> feature_records;
    603   hb_auto_array_t<range_record_t> range_records;
    604   if (num_features)
    605   {
    606     /* Sort features by start/end events. */
    607     hb_auto_array_t<feature_event_t> feature_events;
    608     for (unsigned int i = 0; i < num_features; i++)
    609     {
    610       active_feature_t feature;
    611       feature.rec.tagFeature = hb_uint32_swap (features[i].tag);
    612       feature.rec.lParameter = features[i].value;
    613       feature.order = i;
    614 
    615       feature_event_t *event;
    616 
    617       event = feature_events.push ();
    618       if (unlikely (!event))
    619 	goto fail_features;
    620       event->index = features[i].start;
    621       event->start = true;
    622       event->feature = feature;
    623 
    624       event = feature_events.push ();
    625       if (unlikely (!event))
    626 	goto fail_features;
    627       event->index = features[i].end;
    628       event->start = false;
    629       event->feature = feature;
    630     }
    631     feature_events.qsort ();
    632     /* Add a strategic final event. */
    633     {
    634       active_feature_t feature;
    635       feature.rec.tagFeature = 0;
    636       feature.rec.lParameter = 0;
    637       feature.order = num_features + 1;
    638 
    639       feature_event_t *event = feature_events.push ();
    640       if (unlikely (!event))
    641 	goto fail_features;
    642       event->index = 0; /* This value does magic. */
    643       event->start = false;
    644       event->feature = feature;
    645     }
    646 
    647     /* Scan events and save features for each range. */
    648     hb_auto_array_t<active_feature_t> active_features;
    649     unsigned int last_index = 0;
    650     for (unsigned int i = 0; i < feature_events.len; i++)
    651     {
    652       feature_event_t *event = &feature_events[i];
    653 
    654       if (event->index != last_index)
    655       {
    656         /* Save a snapshot of active features and the range. */
    657 	range_record_t *range = range_records.push ();
    658 	if (unlikely (!range))
    659 	  goto fail_features;
    660 
    661 	unsigned int offset = feature_records.len;
    662 
    663 	active_features.qsort ();
    664 	for (unsigned int j = 0; j < active_features.len; j++)
    665 	{
    666 	  if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature)
    667 	  {
    668 	    OPENTYPE_FEATURE_RECORD *feature = feature_records.push ();
    669 	    if (unlikely (!feature))
    670 	      goto fail_features;
    671 	    *feature = active_features[j].rec;
    672 	  }
    673 	  else
    674 	  {
    675 	    /* Overrides value for existing feature. */
    676 	    feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter;
    677 	  }
    678 	}
    679 
    680 	/* Will convert to pointer after all is ready, since feature_records.array
    681 	 * may move as we grow it. */
    682 	range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
    683 	range->props.cotfRecords = feature_records.len - offset;
    684 	range->index_first = last_index;
    685 	range->index_last  = event->index - 1;
    686 
    687 	last_index = event->index;
    688       }
    689 
    690       if (event->start) {
    691         active_feature_t *feature = active_features.push ();
    692 	if (unlikely (!feature))
    693 	  goto fail_features;
    694 	*feature = event->feature;
    695       } else {
    696         active_feature_t *feature = active_features.find (&event->feature);
    697 	if (feature)
    698 	  active_features.remove (feature - active_features.array);
    699       }
    700     }
    701 
    702     if (!range_records.len) /* No active feature found. */
    703       goto fail_features;
    704 
    705     /* Fixup the pointers. */
    706     for (unsigned int i = 0; i < range_records.len; i++)
    707     {
    708       range_record_t *range = &range_records[i];
    709       range->props.potfRecords = feature_records.array + reinterpret_cast<uintptr_t> (range->props.potfRecords);
    710     }
    711   }
    712   else
    713   {
    714   fail_features:
    715     num_features = 0;
    716   }
    717 
    718 #define FAIL(...) \
    719   HB_STMT_START { \
    720     DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
    721     return false; \
    722   } HB_STMT_END;
    723 
    724   HRESULT hr;
    725 
    726 retry:
    727 
    728   unsigned int scratch_size;
    729   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
    730 
    731 #define ALLOCATE_ARRAY(Type, name, len) \
    732   Type *name = (Type *) scratch; \
    733   { \
    734     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
    735     assert (_consumed <= scratch_size); \
    736     scratch += _consumed; \
    737     scratch_size -= _consumed; \
    738   }
    739 
    740 #define utf16_index() var1.u32
    741 
    742   ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2);
    743 
    744   unsigned int chars_len = 0;
    745   for (unsigned int i = 0; i < buffer->len; i++)
    746   {
    747     hb_codepoint_t c = buffer->info[i].codepoint;
    748     buffer->info[i].utf16_index() = chars_len;
    749     if (likely (c <= 0xFFFFu))
    750       pchars[chars_len++] = c;
    751     else if (unlikely (c > 0x10FFFFu))
    752       pchars[chars_len++] = 0xFFFDu;
    753     else {
    754       pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
    755       pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
    756     }
    757   }
    758 
    759   ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
    760   ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len);
    761 
    762   if (num_features)
    763   {
    764     /* Need log_clusters to assign features. */
    765     chars_len = 0;
    766     for (unsigned int i = 0; i < buffer->len; i++)
    767     {
    768       hb_codepoint_t c = buffer->info[i].codepoint;
    769       unsigned int cluster = buffer->info[i].cluster;
    770       log_clusters[chars_len++] = cluster;
    771       if (hb_in_range (c, 0x10000u, 0x10FFFFu))
    772 	log_clusters[chars_len++] = cluster; /* Surrogates. */
    773     }
    774   }
    775 
    776   /* The -2 in the following is to compensate for possible
    777    * alignment needed after the WORD array.  sizeof(WORD) == 2. */
    778   unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
    779 			   / (sizeof (WORD) +
    780 			      sizeof (SCRIPT_GLYPHPROP) +
    781 			      sizeof (int) +
    782 			      sizeof (GOFFSET) +
    783 			      sizeof (uint32_t));
    784 
    785   ALLOCATE_ARRAY (WORD, glyphs, glyphs_size);
    786   ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size);
    787   ALLOCATE_ARRAY (int, advances, glyphs_size);
    788   ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size);
    789   ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
    790 
    791   /* Note:
    792    * We can't touch the contents of glyph_props.  Our fallback
    793    * implementations of Shape and Place functions use that buffer
    794    * by casting it to a different type.  It works because they
    795    * both agree about it, but if we want to access it here we
    796    * need address that issue first.
    797    */
    798 
    799 #undef ALLOCATE_ARRAY
    800 
    801 #define MAX_ITEMS 256
    802 
    803   SCRIPT_ITEM items[MAX_ITEMS + 1];
    804   SCRIPT_CONTROL bidi_control = {0};
    805   SCRIPT_STATE bidi_state = {0};
    806   ULONG script_tags[MAX_ITEMS];
    807   int item_count;
    808 
    809   /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
    810   //bidi_control.fMergeNeutralItems = true;
    811   *(uint32_t*)&bidi_control |= 1<<24;
    812 
    813   bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
    814   bidi_state.fOverrideDirection = 1;
    815 
    816   hr = funcs->ScriptItemizeOpenType (pchars,
    817 				     chars_len,
    818 				     MAX_ITEMS,
    819 				     &bidi_control,
    820 				     &bidi_state,
    821 				     items,
    822 				     script_tags,
    823 				     &item_count);
    824   if (unlikely (FAILED (hr)))
    825     FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr);
    826 
    827 #undef MAX_ITEMS
    828 
    829   OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language));
    830   hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties;
    831   hb_auto_array_t<int> range_char_counts;
    832 
    833   unsigned int glyphs_offset = 0;
    834   unsigned int glyphs_len;
    835   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
    836   for (unsigned int i = 0; i < item_count; i++)
    837   {
    838     unsigned int chars_offset = items[i].iCharPos;
    839     unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
    840 
    841     if (num_features)
    842     {
    843       range_properties.shrink (0);
    844       range_char_counts.shrink (0);
    845 
    846       range_record_t *last_range = &range_records[0];
    847 
    848       for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++)
    849       {
    850 	range_record_t *range = last_range;
    851 	while (log_clusters[k] < range->index_first)
    852 	  range--;
    853 	while (log_clusters[k] > range->index_last)
    854 	  range++;
    855 	if (!range_properties.len ||
    856 	    &range->props != range_properties[range_properties.len - 1])
    857 	{
    858 	  TEXTRANGE_PROPERTIES **props = range_properties.push ();
    859 	  int *c = range_char_counts.push ();
    860 	  if (unlikely (!props || !c))
    861 	  {
    862 	    range_properties.shrink (0);
    863 	    range_char_counts.shrink (0);
    864 	    break;
    865 	  }
    866 	  *props = &range->props;
    867 	  *c = 1;
    868 	}
    869 	else
    870 	{
    871 	  range_char_counts[range_char_counts.len - 1]++;
    872 	}
    873 
    874 	last_range = range;
    875       }
    876     }
    877 
    878     /* Asking for glyphs in logical order circumvents at least
    879      * one bug in Uniscribe. */
    880     items[i].a.fLogicalOrder = true;
    881 
    882   retry_shape:
    883     hr = funcs->ScriptShapeOpenType (font_data->hdc,
    884 				     &font_data->script_cache,
    885 				     &items[i].a,
    886 				     script_tags[i],
    887 				     language_tag,
    888 				     range_char_counts.array,
    889 				     range_properties.array,
    890 				     range_properties.len,
    891 				     pchars + chars_offset,
    892 				     item_chars_len,
    893 				     glyphs_size - glyphs_offset,
    894 				     /* out */
    895 				     log_clusters + chars_offset,
    896 				     char_props + chars_offset,
    897 				     glyphs + glyphs_offset,
    898 				     glyph_props + glyphs_offset,
    899 				     (int *) &glyphs_len);
    900 
    901     if (unlikely (items[i].a.fNoGlyphIndex))
    902       FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
    903     if (unlikely (hr == E_OUTOFMEMORY))
    904     {
    905       buffer->ensure (buffer->allocated * 2);
    906       if (buffer->in_error)
    907 	FAIL ("Buffer resize failed");
    908       goto retry;
    909     }
    910     if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
    911     {
    912       if (items[i].a.eScript == SCRIPT_UNDEFINED)
    913 	FAIL ("ScriptShapeOpenType() failed: Font doesn't support script");
    914       items[i].a.eScript = SCRIPT_UNDEFINED;
    915       goto retry_shape;
    916     }
    917     if (unlikely (FAILED (hr)))
    918     {
    919       FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
    920     }
    921 
    922     for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
    923       log_clusters[j] += glyphs_offset;
    924 
    925     hr = funcs->ScriptPlaceOpenType (font_data->hdc,
    926 				     &font_data->script_cache,
    927 				     &items[i].a,
    928 				     script_tags[i],
    929 				     language_tag,
    930 				     range_char_counts.array,
    931 				     range_properties.array,
    932 				     range_properties.len,
    933 				     pchars + chars_offset,
    934 				     log_clusters + chars_offset,
    935 				     char_props + chars_offset,
    936 				     item_chars_len,
    937 				     glyphs + glyphs_offset,
    938 				     glyph_props + glyphs_offset,
    939 				     glyphs_len,
    940 				     /* out */
    941 				     advances + glyphs_offset,
    942 				     offsets + glyphs_offset,
    943 				     NULL);
    944     if (unlikely (FAILED (hr)))
    945       FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
    946 
    947     if (DEBUG_ENABLED (UNISCRIBE))
    948       fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
    949 	       i,
    950 	       items[i].a.fRTL,
    951 	       items[i].a.fLayoutRTL,
    952 	       items[i].a.fLogicalOrder,
    953 	       HB_UNTAG (hb_uint32_swap (script_tags[i])));
    954 
    955     glyphs_offset += glyphs_len;
    956   }
    957   glyphs_len = glyphs_offset;
    958 
    959   /* Ok, we've got everything we need, now compose output buffer,
    960    * very, *very*, carefully! */
    961 
    962   /* Calculate visual-clusters.  That's what we ship. */
    963   for (unsigned int i = 0; i < glyphs_len; i++)
    964     vis_clusters[i] = -1;
    965   for (unsigned int i = 0; i < buffer->len; i++) {
    966     uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
    967     *p = MIN (*p, buffer->info[i].cluster);
    968   }
    969   for (unsigned int i = 1; i < glyphs_len; i++)
    970     if (vis_clusters[i] == -1)
    971       vis_clusters[i] = vis_clusters[i - 1];
    972 
    973 #undef utf16_index
    974 
    975   buffer->ensure (glyphs_len);
    976   if (buffer->in_error)
    977     FAIL ("Buffer in error");
    978 
    979 #undef FAIL
    980 
    981   /* Set glyph infos */
    982   buffer->len = 0;
    983   for (unsigned int i = 0; i < glyphs_len; i++)
    984   {
    985     hb_glyph_info_t *info = &buffer->info[buffer->len++];
    986 
    987     info->codepoint = glyphs[i];
    988     info->cluster = vis_clusters[i];
    989 
    990     /* The rest is crap.  Let's store position info there for now. */
    991     info->mask = advances[i];
    992     info->var1.u32 = offsets[i].du;
    993     info->var2.u32 = offsets[i].dv;
    994   }
    995 
    996   /* Set glyph positions */
    997   buffer->clear_positions ();
    998   for (unsigned int i = 0; i < glyphs_len; i++)
    999   {
   1000     hb_glyph_info_t *info = &buffer->info[i];
   1001     hb_glyph_position_t *pos = &buffer->pos[i];
   1002 
   1003     /* TODO vertical */
   1004     pos->x_advance = info->mask;
   1005     pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
   1006     pos->y_offset = info->var2.u32;
   1007   }
   1008 
   1009   if (backward)
   1010     hb_buffer_reverse (buffer);
   1011 
   1012   /* Wow, done! */
   1013   return true;
   1014 }
   1015 
   1016 
   1017