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