gfx/harfbuzz/src/hb-uniscribe.cc

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     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  */
    27 #define _WIN32_WINNT 0x0600
    28 #define WIN32_LEAN_AND_MEAN
    30 #define HB_SHAPER uniscribe
    31 #include "hb-shaper-impl-private.hh"
    33 #include <windows.h>
    34 #include <usp10.h>
    35 #include <rpc.h>
    37 #include "hb-uniscribe.h"
    39 #include "hb-open-file-private.hh"
    40 #include "hb-ot-name-table.hh"
    41 #include "hb-ot-tag.h"
    44 #ifndef HB_DEBUG_UNISCRIBE
    45 #define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
    46 #endif
    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 );
    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 );
    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 );
   101 /* Fallback implementations. */
   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 }
   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 }
   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 }
   194 struct hb_uniscribe_shaper_funcs_t {
   195   SIOT ScriptItemizeOpenType;
   196   SSOT ScriptShapeOpenType;
   197   SPOT ScriptPlaceOpenType;
   199   inline void init (void)
   200   {
   201     HMODULE hinstLib;
   202     this->ScriptItemizeOpenType = NULL;
   203     this->ScriptShapeOpenType   = NULL;
   204     this->ScriptPlaceOpenType   = NULL;
   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;
   226 static inline void
   227 free_uniscribe_funcs (void)
   228 {
   229   free (uniscribe_funcs);
   230 }
   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);
   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;
   244     funcs->init ();
   246     if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) {
   247       free (funcs);
   248       goto retry;
   249     }
   251 #ifdef HAVE_ATEXIT
   252     atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
   253 #endif
   254   }
   256   return funcs;
   257 }
   260 struct active_feature_t {
   261   OPENTYPE_FEATURE_RECORD rec;
   262   unsigned int order;
   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 };
   275 struct feature_event_t {
   276   unsigned int index;
   277   bool start;
   278   active_feature_t feature;
   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 };
   287 struct range_record_t {
   288   TEXTRANGE_PROPERTIES props;
   289   unsigned int index_first; /* == start */
   290   unsigned int index_last;  /* == end - 1 */
   291 };
   293 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face)
   294 HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font)
   297 /*
   298  * shaper face data
   299  */
   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 };
   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 }
   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    */
   349   blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
   351   unsigned int length, new_length, name_str_len;
   352   const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
   354   _hb_generate_unique_face_name (new_name, &name_str_len);
   356   static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
   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;
   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   }
   371   memcpy(new_sfnt_data, orig_sfnt_data, length);
   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   }
   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   }
   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   }
   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. */
   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 }
   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;
   436   data->funcs = hb_uniscribe_shaper_get_funcs ();
   437   if (unlikely (!data->funcs))
   438   {
   439     free (data);
   440     return NULL;
   441   }
   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");
   447   blob = _hb_rename_font (blob, data->face_name);
   448   if (unlikely (!blob))
   449   {
   450     free (data);
   451     return NULL;
   452   }
   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   }
   465   return data;
   466 }
   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 }
   476 /*
   477  * shaper font data
   478  */
   480 struct hb_uniscribe_shaper_font_data_t {
   481   HDC hdc;
   482   LOGFONTW log_font;
   483   HFONT hfont;
   484   SCRIPT_CACHE script_cache;
   485 };
   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;
   495   hb_face_t *face = font->face;
   496   hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   498   memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
   500   return true;
   501 }
   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;
   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;
   512   data->hdc = GetDC (NULL);
   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   }
   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   }
   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   }
   533   return data;
   534 }
   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 }
   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 }
   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 }
   565 /*
   566  * shaper shape_plan data
   567  */
   569 struct hb_uniscribe_shaper_shape_plan_data_t {};
   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 }
   579 void
   580 _hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
   581 {
   582 }
   585 /*
   586  * shaper
   587  */
   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;
   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;
   618       feature_event_t *event;
   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;
   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;
   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     }
   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];
   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;
   664 	unsigned int offset = feature_records.len;
   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 	}
   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;
   690 	last_index = event->index;
   691       }
   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     }
   705     if (!range_records.len) /* No active feature found. */
   706       goto fail_features;
   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   }
   721 #define FAIL(...) \
   722   HB_STMT_START { \
   723     DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
   724     return false; \
   725   } HB_STMT_END;
   727   HRESULT hr;
   729 retry:
   731   unsigned int scratch_size;
   732   hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
   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   }
   743 #define utf16_index() var1.u32
   745   ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2);
   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   }
   762   ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
   763   ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len);
   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   }
   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));
   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);
   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    */
   802 #undef ALLOCATE_ARRAY
   804 #define MAX_ITEMS 256
   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;
   812   /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
   813   //bidi_control.fMergeNeutralItems = true;
   814   *(uint32_t*)&bidi_control |= 1<<24;
   816   bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
   817   bidi_state.fOverrideDirection = 1;
   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);
   830 #undef MAX_ITEMS
   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;
   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;
   844     if (num_features)
   845     {
   846       range_properties.shrink (0);
   847       range_char_counts.shrink (0);
   849       range_record_t *last_range = &range_records[0];
   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 	}
   877 	last_range = range;
   878       }
   879     }
   881     /* Asking for glyphs in logical order circumvents at least
   882      * one bug in Uniscribe. */
   883     items[i].a.fLogicalOrder = true;
   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);
   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     }
   925     for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
   926       log_clusters[j] += glyphs_offset;
   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);
   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])));
   958     glyphs_offset += glyphs_len;
   959   }
   960   glyphs_len = glyphs_offset;
   962   /* Ok, we've got everything we need, now compose output buffer,
   963    * very, *very*, carefully! */
   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];
   976 #undef utf16_index
   978   buffer->ensure (glyphs_len);
   979   if (buffer->in_error)
   980     FAIL ("Buffer in error");
   982 #undef FAIL
   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++];
   990     info->codepoint = glyphs[i];
   991     info->cluster = vis_clusters[i];
   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   }
   999   /* Set glyph positions */
  1000   buffer->clear_positions ();
  1001   for (unsigned int i = 0; i < glyphs_len; i++)
  1003     hb_glyph_info_t *info = &buffer->info[i];
  1004     hb_glyph_position_t *pos = &buffer->pos[i];
  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;
  1012   if (backward)
  1013     hb_buffer_reverse (buffer);
  1015   /* Wow, done! */
  1016   return true;

mercurial