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 HB_USE_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   ASSERT_STATIC (2 + 3 * (16/2) < LF_FACESIZE);
    314   unsigned int name_str_len = 0;
    315   face_name[name_str_len++] = 'F';
    316   face_name[name_str_len++] = '_';
    317   unsigned char *p = (unsigned char *) &id;
    318   for (unsigned int i = 0; i < 16; i += 2)
    319   {
    320     /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
    321      * using the bits in groups of 5,5,6 to select chars from enc.
    322      * This will generate 24 characters; with the 'F_' prefix we already provided,
    323      * the name will be 26 chars (plus the NUL terminator), so will always fit within
    324      * face_name (LF_FACESIZE = 32). */
    325     face_name[name_str_len++] = enc[p[i] >> 3];
    326     face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
    327     face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
    328   }
    329   face_name[name_str_len] = 0;
    330   if (plen)
    331     *plen = name_str_len;
    332 }
    333 
    334 /* Destroys blob. */
    335 static hb_blob_t *
    336 _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
    337 {
    338   /* Create a copy of the font data, with the 'name' table replaced by a
    339    * table that names the font with our private F_* name created above.
    340    * For simplicity, we just append a new 'name' table and update the
    341    * sfnt directory; the original table is left in place, but unused.
    342    *
    343    * The new table will contain just 5 name IDs: family, style, unique,
    344    * full, PS. All of them point to the same name data with our unique name.
    345    */
    346 
    347   blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
    348 
    349   unsigned int length, new_length, name_str_len;
    350   const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
    351 
    352   _hb_generate_unique_face_name (new_name, &name_str_len);
    353 
    354   static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
    355 
    356   unsigned int name_table_length = OT::name::min_size +
    357                                    ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size +
    358                                    name_str_len * 2; /* for name data in UTF16BE form */
    359   unsigned int name_table_offset = (length + 3) & ~3;
    360 
    361   new_length = name_table_offset + ((name_table_length + 3) & ~3);
    362   void *new_sfnt_data = calloc (1, new_length);
    363   if (!new_sfnt_data)
    364   {
    365     hb_blob_destroy (blob);
    366     return NULL;
    367   }
    368 
    369   memcpy(new_sfnt_data, orig_sfnt_data, length);
    370 
    371   OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
    372   name.format.set (0);
    373   name.count.set (ARRAY_LENGTH (name_IDs));
    374   name.stringOffset.set (name.get_size ());
    375   for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
    376   {
    377     OT::NameRecord &record = name.nameRecord[i];
    378     record.platformID.set (3);
    379     record.encodingID.set (1);
    380     record.languageID.set (0x0409u); /* English */
    381     record.nameID.set (name_IDs[i]);
    382     record.length.set (name_str_len * 2);
    383     record.offset.set (0);
    384   }
    385 
    386   /* Copy string data from new_name, converting wchar_t to UTF16BE. */
    387   unsigned char *p = &OT::StructAfter<unsigned char> (name);
    388   for (unsigned int i = 0; i < name_str_len; i++)
    389   {
    390     *p++ = new_name[i] >> 8;
    391     *p++ = new_name[i] & 0xff;
    392   }
    393 
    394   /* Adjust name table entry to point to new name table */
    395   const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data);
    396   unsigned int face_count = file.get_face_count ();
    397   for (unsigned int face_index = 0; face_index < face_count; face_index++)
    398   {
    399     /* Note: doing multiple edits (ie. TTC) can be unsafe.  There may be
    400      * toe-stepping.  But we don't really care. */
    401     const OT::OpenTypeFontFace &face = file.get_face (face_index);
    402     unsigned int index;
    403     if (face.find_table_index (HB_OT_TAG_name, &index))
    404     {
    405       OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
    406       record.checkSum.set_for_data (&name, name_table_length);
    407       record.offset.set (name_table_offset);
    408       record.length.set (name_table_length);
    409     }
    410     else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
    411     {
    412       free (new_sfnt_data);
    413       hb_blob_destroy (blob);
    414       return NULL;
    415     }
    416   }
    417 
    418   /* The checkSumAdjustment field in the 'head' table is now wrong,
    419    * but that doesn't actually seem to cause any problems so we don't
    420    * bother. */
    421 
    422   hb_blob_destroy (blob);
    423   return hb_blob_create ((const char *) new_sfnt_data, new_length,
    424 			 HB_MEMORY_MODE_WRITABLE, NULL, free);
    425 }
    426 
    427 hb_uniscribe_shaper_face_data_t *
    428 _hb_uniscribe_shaper_face_data_create (hb_face_t *face)
    429 {
    430   hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
    431   if (unlikely (!data))
    432     return NULL;
    433 
    434   data->funcs = hb_uniscribe_shaper_get_funcs ();
    435   if (unlikely (!data->funcs))
    436   {
    437     free (data);
    438     return NULL;
    439   }
    440 
    441   hb_blob_t *blob = hb_face_reference_blob (face);
    442   if (unlikely (!hb_blob_get_length (blob)))
    443     DEBUG_MSG (UNISCRIBE, face, "Face has empty blob");
    444 
    445   blob = _hb_rename_font (blob, data->face_name);
    446   if (unlikely (!blob))
    447   {
    448     free (data);
    449     return NULL;
    450   }
    451 
    452   DWORD num_fonts_installed;
    453   data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL),
    454 				   hb_blob_get_length (blob),
    455 				   0, &num_fonts_installed);
    456   if (unlikely (!data->fh))
    457   {
    458     DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
    459     free (data);
    460     return NULL;
    461   }
    462 
    463   return data;
    464 }
    465 
    466 void
    467 _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
    468 {
    469   RemoveFontMemResourceEx (data->fh);
    470   free (data);
    471 }
    472 
    473 
    474 /*
    475  * shaper font data
    476  */
    477 
    478 struct hb_uniscribe_shaper_font_data_t {
    479   HDC hdc;
    480   LOGFONTW log_font;
    481   HFONT hfont;
    482   SCRIPT_CACHE script_cache;
    483 };
    484 
    485 static bool
    486 populate_log_font (LOGFONTW  *lf,
    487 		   hb_font_t *font)
    488 {
    489   memset (lf, 0, sizeof (*lf));
    490   lf->lfHeight = -font->y_scale;
    491   lf->lfCharSet = DEFAULT_CHARSET;
    492 
    493   hb_face_t *face = font->face;
    494   hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    495 
    496   memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
    497 
    498   return true;
    499 }
    500 
    501 hb_uniscribe_shaper_font_data_t *
    502 _hb_uniscribe_shaper_font_data_create (hb_font_t *font)
    503 {
    504   if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL;
    505 
    506   hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
    507   if (unlikely (!data))
    508     return NULL;
    509 
    510   data->hdc = GetDC (NULL);
    511 
    512   if (unlikely (!populate_log_font (&data->log_font, font))) {
    513     DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
    514     _hb_uniscribe_shaper_font_data_destroy (data);
    515     return NULL;
    516   }
    517 
    518   data->hfont = CreateFontIndirectW (&data->log_font);
    519   if (unlikely (!data->hfont)) {
    520     DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
    521     _hb_uniscribe_shaper_font_data_destroy (data);
    522      return NULL;
    523   }
    524 
    525   if (!SelectObject (data->hdc, data->hfont)) {
    526     DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
    527     _hb_uniscribe_shaper_font_data_destroy (data);
    528      return NULL;
    529   }
    530 
    531   return data;
    532 }
    533 
    534 void
    535 _hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
    536 {
    537   if (data->hdc)
    538     ReleaseDC (NULL, data->hdc);
    539   if (data->hfont)
    540     DeleteObject (data->hfont);
    541   if (data->script_cache)
    542     ScriptFreeCache (&data->script_cache);
    543   free (data);
    544 }
    545 
    546 LOGFONTW *
    547 hb_uniscribe_font_get_logfontw (hb_font_t *font)
    548 {
    549   if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
    550   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
    551   return &font_data->log_font;
    552 }
    553 
    554 HFONT
    555 hb_uniscribe_font_get_hfont (hb_font_t *font)
    556 {
    557   if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
    558   hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
    559   return font_data->hfont;
    560 }
    561 
    562 
    563 /*
    564  * shaper shape_plan data
    565  */
    566 
    567 struct hb_uniscribe_shaper_shape_plan_data_t {};
    568 
    569 hb_uniscribe_shaper_shape_plan_data_t *
    570 _hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
    571 					     const hb_feature_t *user_features HB_UNUSED,
    572 					     unsigned int        num_user_features HB_UNUSED)
    573 {
    574   return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
    575 }
    576 
    577 void
    578 _hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
    579 {
    580 }
    581 
    582 
    583 /*
    584  * shaper
    585  */
    586 
    587 
    588 hb_bool_t
    589 _hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
    590 		     hb_font_t          *font,
    591 		     hb_buffer_t        *buffer,
    592 		     const hb_feature_t *features,
    593 		     unsigned int        num_features)
    594 {
    595   hb_face_t *face = font->face;
    596   hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
    597   hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
    598   hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
    599 
    600   /*
    601    * Set up features.
    602    */
    603   hb_auto_array_t<OPENTYPE_FEATURE_RECORD> feature_records;
    604   hb_auto_array_t<range_record_t> range_records;
    605   if (num_features)
    606   {
    607     /* Sort features by start/end events. */
    608     hb_auto_array_t<feature_event_t> feature_events;
    609     for (unsigned int i = 0; i < num_features; i++)
    610     {
    611       active_feature_t feature;
    612       feature.rec.tagFeature = hb_uint32_swap (features[i].tag);
    613       feature.rec.lParameter = features[i].value;
    614       feature.order = i;
    615 
    616       feature_event_t *event;
    617 
    618       event = feature_events.push ();
    619       if (unlikely (!event))
    620 	goto fail_features;
    621       event->index = features[i].start;
    622       event->start = true;
    623       event->feature = feature;
    624 
    625       event = feature_events.push ();
    626       if (unlikely (!event))
    627 	goto fail_features;
    628       event->index = features[i].end;
    629       event->start = false;
    630       event->feature = feature;
    631     }
    632     feature_events.qsort ();
    633     /* Add a strategic final event. */
    634     {
    635       active_feature_t feature;
    636       feature.rec.tagFeature = 0;
    637       feature.rec.lParameter = 0;
    638       feature.order = num_features + 1;
    639 
    640       feature_event_t *event = feature_events.push ();
    641       if (unlikely (!event))
    642 	goto fail_features;
    643       event->index = 0; /* This value does magic. */
    644       event->start = false;
    645       event->feature = feature;
    646     }
    647 
    648     /* Scan events and save features for each range. */
    649     hb_auto_array_t<active_feature_t> active_features;
    650     unsigned int last_index = 0;
    651     for (unsigned int i = 0; i < feature_events.len; i++)
    652     {
    653       feature_event_t *event = &feature_events[i];
    654 
    655       if (event->index != last_index)
    656       {
    657         /* Save a snapshot of active features and the range. */
    658 	range_record_t *range = range_records.push ();
    659 	if (unlikely (!range))
    660 	  goto fail_features;
    661 
    662 	unsigned int offset = feature_records.len;
    663 
    664 	active_features.qsort ();
    665 	for (unsigned int j = 0; j < active_features.len; j++)
    666 	{
    667 	  if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature)
    668 	  {
    669 	    OPENTYPE_FEATURE_RECORD *feature = feature_records.push ();
    670 	    if (unlikely (!feature))
    671 	      goto fail_features;
    672 	    *feature = active_features[j].rec;
    673 	  }
    674 	  else
    675 	  {
    676 	    /* Overrides value for existing feature. */
    677 	    feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter;
    678 	  }
    679 	}
    680 
    681 	/* Will convert to pointer after all is ready, since feature_records.array
    682 	 * may move as we grow it. */
    683 	range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
    684 	range->props.cotfRecords = feature_records.len - offset;
    685 	range->index_first = last_index;
    686 	range->index_last  = event->index - 1;
    687 
    688 	last_index = event->index;
    689       }
    690 
    691       if (event->start) {
    692         active_feature_t *feature = active_features.push ();
    693 	if (unlikely (!feature))
    694 	  goto fail_features;
    695 	*feature = event->feature;
    696       } else {
    697         active_feature_t *feature = active_features.find (&event->feature);
    698 	if (feature)
    699 	  active_features.remove (feature - active_features.array);
    700       }
    701     }
    702 
    703     if (!range_records.len) /* No active feature found. */
    704       goto fail_features;
    705 
    706     /* Fixup the pointers. */
    707     for (unsigned int i = 0; i < range_records.len; i++)
    708     {
    709       range_record_t *range = &range_records[i];
    710       range->props.potfRecords = feature_records.array + reinterpret_cast<uintptr_t> (range->props.potfRecords);
    711     }
    712   }
    713   else
    714   {
    715   fail_features:
    716     num_features = 0;
    717   }
    718 
    719 #define FAIL(...) \
    720   HB_STMT_START { \
    721     DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
    722     return false; \
    723   } HB_STMT_END;
    724 
    725   HRESULT hr;
    726 
    727 retry:
    728 
    729   unsigned int scratch_size;
    730   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
    731 
    732 #define ALLOCATE_ARRAY(Type, name, len) \
    733   Type *name = (Type *) scratch; \
    734   { \
    735     unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
    736     assert (_consumed <= scratch_size); \
    737     scratch += _consumed; \
    738     scratch_size -= _consumed; \
    739   }
    740 
    741 #define utf16_index() var1.u32
    742 
    743   ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2);
    744 
    745   unsigned int chars_len = 0;
    746   for (unsigned int i = 0; i < buffer->len; i++)
    747   {
    748     hb_codepoint_t c = buffer->info[i].codepoint;
    749     buffer->info[i].utf16_index() = chars_len;
    750     if (likely (c <= 0xFFFFu))
    751       pchars[chars_len++] = c;
    752     else if (unlikely (c > 0x10FFFFu))
    753       pchars[chars_len++] = 0xFFFDu;
    754     else {
    755       pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
    756       pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1 << 10) - 1));
    757     }
    758   }
    759 
    760   ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
    761   ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len);
    762 
    763   if (num_features)
    764   {
    765     /* Need log_clusters to assign features. */
    766     chars_len = 0;
    767     for (unsigned int i = 0; i < buffer->len; i++)
    768     {
    769       hb_codepoint_t c = buffer->info[i].codepoint;
    770       unsigned int cluster = buffer->info[i].cluster;
    771       log_clusters[chars_len++] = cluster;
    772       if (hb_in_range (c, 0x10000u, 0x10FFFFu))
    773 	log_clusters[chars_len++] = cluster; /* Surrogates. */
    774     }
    775   }
    776 
    777   /* The -2 in the following is to compensate for possible
    778    * alignment needed after the WORD array.  sizeof(WORD) == 2. */
    779   unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
    780 			   / (sizeof (WORD) +
    781 			      sizeof (SCRIPT_GLYPHPROP) +
    782 			      sizeof (int) +
    783 			      sizeof (GOFFSET) +
    784 			      sizeof (uint32_t));
    785 
    786   ALLOCATE_ARRAY (WORD, glyphs, glyphs_size);
    787   ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size);
    788   ALLOCATE_ARRAY (int, advances, glyphs_size);
    789   ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size);
    790   ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
    791 
    792   /* Note:
    793    * We can't touch the contents of glyph_props.  Our fallback
    794    * implementations of Shape and Place functions use that buffer
    795    * by casting it to a different type.  It works because they
    796    * both agree about it, but if we want to access it here we
    797    * need address that issue first.
    798    */
    799 
    800 #undef ALLOCATE_ARRAY
    801 
    802 #define MAX_ITEMS 256
    803 
    804   SCRIPT_ITEM items[MAX_ITEMS + 1];
    805   SCRIPT_CONTROL bidi_control = {0};
    806   SCRIPT_STATE bidi_state = {0};
    807   ULONG script_tags[MAX_ITEMS];
    808   int item_count;
    809 
    810   /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
    811   //bidi_control.fMergeNeutralItems = true;
    812   *(uint32_t*)&bidi_control |= 1<<24;
    813 
    814   bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
    815   bidi_state.fOverrideDirection = 1;
    816 
    817   hr = funcs->ScriptItemizeOpenType (pchars,
    818 				     chars_len,
    819 				     MAX_ITEMS,
    820 				     &bidi_control,
    821 				     &bidi_state,
    822 				     items,
    823 				     script_tags,
    824 				     &item_count);
    825   if (unlikely (FAILED (hr)))
    826     FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr);
    827 
    828 #undef MAX_ITEMS
    829 
    830   OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language));
    831   hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties;
    832   hb_auto_array_t<int> range_char_counts;
    833 
    834   unsigned int glyphs_offset = 0;
    835   unsigned int glyphs_len;
    836   bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
    837   for (unsigned int i = 0; i < item_count; i++)
    838   {
    839     unsigned int chars_offset = items[i].iCharPos;
    840     unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
    841 
    842     if (num_features)
    843     {
    844       range_properties.shrink (0);
    845       range_char_counts.shrink (0);
    846 
    847       range_record_t *last_range = &range_records[0];
    848 
    849       for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++)
    850       {
    851 	range_record_t *range = last_range;
    852 	while (log_clusters[k] < range->index_first)
    853 	  range--;
    854 	while (log_clusters[k] > range->index_last)
    855 	  range++;
    856 	if (!range_properties.len ||
    857 	    &range->props != range_properties[range_properties.len - 1])
    858 	{
    859 	  TEXTRANGE_PROPERTIES **props = range_properties.push ();
    860 	  int *c = range_char_counts.push ();
    861 	  if (unlikely (!props || !c))
    862 	  {
    863 	    range_properties.shrink (0);
    864 	    range_char_counts.shrink (0);
    865 	    break;
    866 	  }
    867 	  *props = &range->props;
    868 	  *c = 1;
    869 	}
    870 	else
    871 	{
    872 	  range_char_counts[range_char_counts.len - 1]++;
    873 	}
    874 
    875 	last_range = range;
    876       }
    877     }
    878 
    879     /* Asking for glyphs in logical order circumvents at least
    880      * one bug in Uniscribe. */
    881     items[i].a.fLogicalOrder = true;
    882 
    883   retry_shape:
    884     hr = funcs->ScriptShapeOpenType (font_data->hdc,
    885 				     &font_data->script_cache,
    886 				     &items[i].a,
    887 				     script_tags[i],
    888 				     language_tag,
    889 				     range_char_counts.array,
    890 				     range_properties.array,
    891 				     range_properties.len,
    892 				     pchars + chars_offset,
    893 				     item_chars_len,
    894 				     glyphs_size - glyphs_offset,
    895 				     /* out */
    896 				     log_clusters + chars_offset,
    897 				     char_props + chars_offset,
    898 				     glyphs + glyphs_offset,
    899 				     glyph_props + glyphs_offset,
    900 				     (int *) &glyphs_len);
    901 
    902     if (unlikely (items[i].a.fNoGlyphIndex))
    903       FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
    904     if (unlikely (hr == E_OUTOFMEMORY))
    905     {
    906       if (unlikely (!buffer->ensure (buffer->allocated * 2)))
    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   if (unlikely (!buffer->ensure (glyphs_len)))
    976     FAIL ("Buffer in error");
    977 
    978 #undef FAIL
    979 
    980   /* Set glyph infos */
    981   buffer->len = 0;
    982   for (unsigned int i = 0; i < glyphs_len; i++)
    983   {
    984     hb_glyph_info_t *info = &buffer->info[buffer->len++];
    985 
    986     info->codepoint = glyphs[i];
    987     info->cluster = vis_clusters[i];
    988 
    989     /* The rest is crap.  Let's store position info there for now. */
    990     info->mask = advances[i];
    991     info->var1.u32 = offsets[i].du;
    992     info->var2.u32 = offsets[i].dv;
    993   }
    994 
    995   /* Set glyph positions */
    996   buffer->clear_positions ();
    997   for (unsigned int i = 0; i < glyphs_len; i++)
    998   {
    999     hb_glyph_info_t *info = &buffer->info[i];
   1000     hb_glyph_position_t *pos = &buffer->pos[i];
   1001 
   1002     /* TODO vertical */
   1003     pos->x_advance = info->mask;
   1004     pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
   1005     pos->y_offset = info->var2.u32;
   1006   }
   1007 
   1008   if (backward)
   1009     hb_buffer_reverse (buffer);
   1010 
   1011   /* Wow, done! */
   1012   return true;
   1013 }
   1014 
   1015 
   1016