gfx/harfbuzz/src/hb-uniscribe.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/harfbuzz/src/hb-uniscribe.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1019 @@
     1.4 +/*
     1.5 + * Copyright © 2011,2012,2013  Google, Inc.
     1.6 + *
     1.7 + *  This is part of HarfBuzz, a text shaping library.
     1.8 + *
     1.9 + * Permission is hereby granted, without written agreement and without
    1.10 + * license or royalty fees, to use, copy, modify, and distribute this
    1.11 + * software and its documentation for any purpose, provided that the
    1.12 + * above copyright notice and the following two paragraphs appear in
    1.13 + * all copies of this software.
    1.14 + *
    1.15 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    1.16 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    1.17 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    1.18 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    1.19 + * DAMAGE.
    1.20 + *
    1.21 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    1.22 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    1.23 + * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    1.24 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    1.25 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    1.26 + *
    1.27 + * Google Author(s): Behdad Esfahbod
    1.28 + */
    1.29 +
    1.30 +#define _WIN32_WINNT 0x0600
    1.31 +#define WIN32_LEAN_AND_MEAN
    1.32 +
    1.33 +#define HB_SHAPER uniscribe
    1.34 +#include "hb-shaper-impl-private.hh"
    1.35 +
    1.36 +#include <windows.h>
    1.37 +#include <usp10.h>
    1.38 +#include <rpc.h>
    1.39 +
    1.40 +#include "hb-uniscribe.h"
    1.41 +
    1.42 +#include "hb-open-file-private.hh"
    1.43 +#include "hb-ot-name-table.hh"
    1.44 +#include "hb-ot-tag.h"
    1.45 +
    1.46 +
    1.47 +#ifndef HB_DEBUG_UNISCRIBE
    1.48 +#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
    1.49 +#endif
    1.50 +
    1.51 +
    1.52 +typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
    1.53 +  const WCHAR *pwcInChars,
    1.54 +  int cInChars,
    1.55 +  int cMaxItems,
    1.56 +  const SCRIPT_CONTROL *psControl,
    1.57 +  const SCRIPT_STATE *psState,
    1.58 +  SCRIPT_ITEM *pItems,
    1.59 +  OPENTYPE_TAG *pScriptTags,
    1.60 +  int *pcItems
    1.61 +);
    1.62 +
    1.63 +typedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/(
    1.64 +  HDC hdc,
    1.65 +  SCRIPT_CACHE *psc,
    1.66 +  SCRIPT_ANALYSIS *psa,
    1.67 +  OPENTYPE_TAG tagScript,
    1.68 +  OPENTYPE_TAG tagLangSys,
    1.69 +  int *rcRangeChars,
    1.70 +  TEXTRANGE_PROPERTIES **rpRangeProperties,
    1.71 +  int cRanges,
    1.72 +  const WCHAR *pwcChars,
    1.73 +  int cChars,
    1.74 +  int cMaxGlyphs,
    1.75 +  WORD *pwLogClust,
    1.76 +  SCRIPT_CHARPROP *pCharProps,
    1.77 +  WORD *pwOutGlyphs,
    1.78 +  SCRIPT_GLYPHPROP *pOutGlyphProps,
    1.79 +  int *pcGlyphs
    1.80 +);
    1.81 +
    1.82 +typedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/(
    1.83 +  HDC hdc,
    1.84 +  SCRIPT_CACHE *psc,
    1.85 +  SCRIPT_ANALYSIS *psa,
    1.86 +  OPENTYPE_TAG tagScript,
    1.87 +  OPENTYPE_TAG tagLangSys,
    1.88 +  int *rcRangeChars,
    1.89 +  TEXTRANGE_PROPERTIES **rpRangeProperties,
    1.90 +  int cRanges,
    1.91 +  const WCHAR *pwcChars,
    1.92 +  WORD *pwLogClust,
    1.93 +  SCRIPT_CHARPROP *pCharProps,
    1.94 +  int cChars,
    1.95 +  const WORD *pwGlyphs,
    1.96 +  const SCRIPT_GLYPHPROP *pGlyphProps,
    1.97 +  int cGlyphs,
    1.98 +  int *piAdvance,
    1.99 +  GOFFSET *pGoffset,
   1.100 +  ABC *pABC
   1.101 +);
   1.102 +
   1.103 +
   1.104 +/* Fallback implementations. */
   1.105 +
   1.106 +static HRESULT WINAPI
   1.107 +hb_ScriptItemizeOpenType(
   1.108 +  const WCHAR *pwcInChars,
   1.109 +  int cInChars,
   1.110 +  int cMaxItems,
   1.111 +  const SCRIPT_CONTROL *psControl,
   1.112 +  const SCRIPT_STATE *psState,
   1.113 +  SCRIPT_ITEM *pItems,
   1.114 +  OPENTYPE_TAG *pScriptTags,
   1.115 +  int *pcItems
   1.116 +)
   1.117 +{
   1.118 +{
   1.119 +  return ScriptItemize (pwcInChars,
   1.120 +			cInChars,
   1.121 +			cMaxItems,
   1.122 +			psControl,
   1.123 +			psState,
   1.124 +			pItems,
   1.125 +			pcItems);
   1.126 +}
   1.127 +}
   1.128 +
   1.129 +static HRESULT WINAPI
   1.130 +hb_ScriptShapeOpenType(
   1.131 +  HDC hdc,
   1.132 +  SCRIPT_CACHE *psc,
   1.133 +  SCRIPT_ANALYSIS *psa,
   1.134 +  OPENTYPE_TAG tagScript,
   1.135 +  OPENTYPE_TAG tagLangSys,
   1.136 +  int *rcRangeChars,
   1.137 +  TEXTRANGE_PROPERTIES **rpRangeProperties,
   1.138 +  int cRanges,
   1.139 +  const WCHAR *pwcChars,
   1.140 +  int cChars,
   1.141 +  int cMaxGlyphs,
   1.142 +  WORD *pwLogClust,
   1.143 +  SCRIPT_CHARPROP *pCharProps,
   1.144 +  WORD *pwOutGlyphs,
   1.145 +  SCRIPT_GLYPHPROP *pOutGlyphProps,
   1.146 +  int *pcGlyphs
   1.147 +)
   1.148 +{
   1.149 +  SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps;
   1.150 +  return ScriptShape (hdc,
   1.151 +		      psc,
   1.152 +		      pwcChars,
   1.153 +		      cChars,
   1.154 +		      cMaxGlyphs,
   1.155 +		      psa,
   1.156 +		      pwOutGlyphs,
   1.157 +		      pwLogClust,
   1.158 +		      psva,
   1.159 +		      pcGlyphs);
   1.160 +}
   1.161 +
   1.162 +static HRESULT WINAPI
   1.163 +hb_ScriptPlaceOpenType(
   1.164 +  HDC hdc,
   1.165 +  SCRIPT_CACHE *psc,
   1.166 +  SCRIPT_ANALYSIS *psa,
   1.167 +  OPENTYPE_TAG tagScript,
   1.168 +  OPENTYPE_TAG tagLangSys,
   1.169 +  int *rcRangeChars,
   1.170 +  TEXTRANGE_PROPERTIES **rpRangeProperties,
   1.171 +  int cRanges,
   1.172 +  const WCHAR *pwcChars,
   1.173 +  WORD *pwLogClust,
   1.174 +  SCRIPT_CHARPROP *pCharProps,
   1.175 +  int cChars,
   1.176 +  const WORD *pwGlyphs,
   1.177 +  const SCRIPT_GLYPHPROP *pGlyphProps,
   1.178 +  int cGlyphs,
   1.179 +  int *piAdvance,
   1.180 +  GOFFSET *pGoffset,
   1.181 +  ABC *pABC
   1.182 +)
   1.183 +{
   1.184 +  SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pGlyphProps;
   1.185 +  return ScriptPlace (hdc,
   1.186 +		      psc,
   1.187 +		      pwGlyphs,
   1.188 +		      cGlyphs,
   1.189 +		      psva,
   1.190 +		      psa,
   1.191 +		      piAdvance,
   1.192 +		      pGoffset,
   1.193 +		      pABC);
   1.194 +}
   1.195 +
   1.196 +
   1.197 +struct hb_uniscribe_shaper_funcs_t {
   1.198 +  SIOT ScriptItemizeOpenType;
   1.199 +  SSOT ScriptShapeOpenType;
   1.200 +  SPOT ScriptPlaceOpenType;
   1.201 +
   1.202 +  inline void init (void)
   1.203 +  {
   1.204 +    HMODULE hinstLib;
   1.205 +    this->ScriptItemizeOpenType = NULL;
   1.206 +    this->ScriptShapeOpenType   = NULL;
   1.207 +    this->ScriptPlaceOpenType   = NULL;
   1.208 +
   1.209 +    hinstLib = GetModuleHandle (TEXT ("usp10.dll"));
   1.210 +    if (hinstLib)
   1.211 +    {
   1.212 +      this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType");
   1.213 +      this->ScriptShapeOpenType   = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType");
   1.214 +      this->ScriptPlaceOpenType   = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType");
   1.215 +    }
   1.216 +    if (!this->ScriptItemizeOpenType ||
   1.217 +	!this->ScriptShapeOpenType   ||
   1.218 +	!this->ScriptPlaceOpenType)
   1.219 +    {
   1.220 +      DEBUG_MSG (UNISCRIBE, NULL, "OpenType versions of functions not found; falling back.");
   1.221 +      this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType;
   1.222 +      this->ScriptShapeOpenType   = hb_ScriptShapeOpenType;
   1.223 +      this->ScriptPlaceOpenType   = hb_ScriptPlaceOpenType;
   1.224 +    }
   1.225 +  }
   1.226 +};
   1.227 +static hb_uniscribe_shaper_funcs_t *uniscribe_funcs;
   1.228 +
   1.229 +static inline void
   1.230 +free_uniscribe_funcs (void)
   1.231 +{
   1.232 +  free (uniscribe_funcs);
   1.233 +}
   1.234 +
   1.235 +static hb_uniscribe_shaper_funcs_t *
   1.236 +hb_uniscribe_shaper_get_funcs (void)
   1.237 +{
   1.238 +retry:
   1.239 +  hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs);
   1.240 +
   1.241 +  if (unlikely (!funcs))
   1.242 +  {
   1.243 +    funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
   1.244 +    if (unlikely (!funcs))
   1.245 +      return NULL;
   1.246 +
   1.247 +    funcs->init ();
   1.248 +
   1.249 +    if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) {
   1.250 +      free (funcs);
   1.251 +      goto retry;
   1.252 +    }
   1.253 +
   1.254 +#ifdef HAVE_ATEXIT
   1.255 +    atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
   1.256 +#endif
   1.257 +  }
   1.258 +
   1.259 +  return funcs;
   1.260 +}
   1.261 +
   1.262 +
   1.263 +struct active_feature_t {
   1.264 +  OPENTYPE_FEATURE_RECORD rec;
   1.265 +  unsigned int order;
   1.266 +
   1.267 +  static int cmp (const active_feature_t *a, const active_feature_t *b) {
   1.268 +    return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 :
   1.269 +	   a->order < b->order ? -1 : a->order > b->order ? 1 :
   1.270 +	   a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 :
   1.271 +	   0;
   1.272 +  }
   1.273 +  bool operator== (const active_feature_t *f) {
   1.274 +    return cmp (this, f) == 0;
   1.275 +  }
   1.276 +};
   1.277 +
   1.278 +struct feature_event_t {
   1.279 +  unsigned int index;
   1.280 +  bool start;
   1.281 +  active_feature_t feature;
   1.282 +
   1.283 +  static int cmp (const feature_event_t *a, const feature_event_t *b) {
   1.284 +    return a->index < b->index ? -1 : a->index > b->index ? 1 :
   1.285 +	   a->start < b->start ? -1 : a->start > b->start ? 1 :
   1.286 +	   active_feature_t::cmp (&a->feature, &b->feature);
   1.287 +  }
   1.288 +};
   1.289 +
   1.290 +struct range_record_t {
   1.291 +  TEXTRANGE_PROPERTIES props;
   1.292 +  unsigned int index_first; /* == start */
   1.293 +  unsigned int index_last;  /* == end - 1 */
   1.294 +};
   1.295 +
   1.296 +HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, face)
   1.297 +HB_SHAPER_DATA_ENSURE_DECLARE(uniscribe, font)
   1.298 +
   1.299 +
   1.300 +/*
   1.301 + * shaper face data
   1.302 + */
   1.303 +
   1.304 +struct hb_uniscribe_shaper_face_data_t {
   1.305 +  HANDLE fh;
   1.306 +  hb_uniscribe_shaper_funcs_t *funcs;
   1.307 +  wchar_t face_name[LF_FACESIZE];
   1.308 +};
   1.309 +
   1.310 +/* face_name should point to a wchar_t[LF_FACESIZE] object. */
   1.311 +static void
   1.312 +_hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen)
   1.313 +{
   1.314 +  /* We'll create a private name for the font from a UUID using a simple,
   1.315 +   * somewhat base64-like encoding scheme */
   1.316 +  const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
   1.317 +  UUID id;
   1.318 +  UuidCreate ((UUID*) &id);
   1.319 +  unsigned int name_str_len = 0;
   1.320 +  face_name[name_str_len++] = 'F';
   1.321 +  face_name[name_str_len++] = '_';
   1.322 +  unsigned char *p = (unsigned char *) &id;
   1.323 +  for (unsigned int i = 0; i < 16; i += 2)
   1.324 +  {
   1.325 +    /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
   1.326 +     * using the bits in groups of 5,5,6 to select chars from enc.
   1.327 +     * This will generate 24 characters; with the 'F_' prefix we already provided,
   1.328 +     * the name will be 26 chars (plus the NUL terminator), so will always fit within
   1.329 +     * face_name (LF_FACESIZE = 32). */
   1.330 +    face_name[name_str_len++] = enc[p[i] >> 3];
   1.331 +    face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
   1.332 +    face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
   1.333 +  }
   1.334 +  face_name[name_str_len] = 0;
   1.335 +  if (plen)
   1.336 +    *plen = name_str_len;
   1.337 +}
   1.338 +
   1.339 +/* Destroys blob. */
   1.340 +static hb_blob_t *
   1.341 +_hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
   1.342 +{
   1.343 +  /* Create a copy of the font data, with the 'name' table replaced by a
   1.344 +   * table that names the font with our private F_* name created above.
   1.345 +   * For simplicity, we just append a new 'name' table and update the
   1.346 +   * sfnt directory; the original table is left in place, but unused.
   1.347 +   *
   1.348 +   * The new table will contain just 5 name IDs: family, style, unique,
   1.349 +   * full, PS. All of them point to the same name data with our unique name.
   1.350 +   */
   1.351 +
   1.352 +  blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
   1.353 +
   1.354 +  unsigned int length, new_length, name_str_len;
   1.355 +  const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
   1.356 +
   1.357 +  _hb_generate_unique_face_name (new_name, &name_str_len);
   1.358 +
   1.359 +  static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
   1.360 +
   1.361 +  unsigned int name_table_length = OT::name::min_size +
   1.362 +                                   ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size +
   1.363 +                                   name_str_len * 2; /* for name data in UTF16BE form */
   1.364 +  unsigned int name_table_offset = (length + 3) & ~3;
   1.365 +
   1.366 +  new_length = name_table_offset + ((name_table_length + 3) & ~3);
   1.367 +  void *new_sfnt_data = calloc (1, new_length);
   1.368 +  if (!new_sfnt_data)
   1.369 +  {
   1.370 +    hb_blob_destroy (blob);
   1.371 +    return NULL;
   1.372 +  }
   1.373 +
   1.374 +  memcpy(new_sfnt_data, orig_sfnt_data, length);
   1.375 +
   1.376 +  OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
   1.377 +  name.format.set (0);
   1.378 +  name.count.set (ARRAY_LENGTH (name_IDs));
   1.379 +  name.stringOffset.set (name.get_size ());
   1.380 +  for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
   1.381 +  {
   1.382 +    OT::NameRecord &record = name.nameRecord[i];
   1.383 +    record.platformID.set (3);
   1.384 +    record.encodingID.set (1);
   1.385 +    record.languageID.set (0x0409); /* English */
   1.386 +    record.nameID.set (name_IDs[i]);
   1.387 +    record.length.set (name_str_len * 2);
   1.388 +    record.offset.set (0);
   1.389 +  }
   1.390 +
   1.391 +  /* Copy string data from new_name, converting wchar_t to UTF16BE. */
   1.392 +  unsigned char *p = &OT::StructAfter<unsigned char> (name);
   1.393 +  for (unsigned int i = 0; i < name_str_len; i++)
   1.394 +  {
   1.395 +    *p++ = new_name[i] >> 8;
   1.396 +    *p++ = new_name[i] & 0xff;
   1.397 +  }
   1.398 +
   1.399 +  /* Adjust name table entry to point to new name table */
   1.400 +  const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data);
   1.401 +  unsigned int face_count = file.get_face_count ();
   1.402 +  for (unsigned int face_index = 0; face_index < face_count; face_index++)
   1.403 +  {
   1.404 +    /* Note: doing multiple edits (ie. TTC) can be unsafe.  There may be
   1.405 +     * toe-stepping.  But we don't really care. */
   1.406 +    const OT::OpenTypeFontFace &face = file.get_face (face_index);
   1.407 +    unsigned int index;
   1.408 +    if (face.find_table_index (HB_OT_TAG_name, &index))
   1.409 +    {
   1.410 +      OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
   1.411 +      record.checkSum.set_for_data (&name, name_table_length);
   1.412 +      record.offset.set (name_table_offset);
   1.413 +      record.length.set (name_table_length);
   1.414 +    }
   1.415 +    else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
   1.416 +    {
   1.417 +      free (new_sfnt_data);
   1.418 +      hb_blob_destroy (blob);
   1.419 +      return NULL;
   1.420 +    }
   1.421 +  }
   1.422 +
   1.423 +  /* The checkSumAdjustment field in the 'head' table is now wrong,
   1.424 +   * but that doesn't actually seem to cause any problems so we don't
   1.425 +   * bother. */
   1.426 +
   1.427 +  hb_blob_destroy (blob);
   1.428 +  return hb_blob_create ((const char *) new_sfnt_data, new_length,
   1.429 +			 HB_MEMORY_MODE_WRITABLE, NULL, free);
   1.430 +}
   1.431 +
   1.432 +hb_uniscribe_shaper_face_data_t *
   1.433 +_hb_uniscribe_shaper_face_data_create (hb_face_t *face)
   1.434 +{
   1.435 +  hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
   1.436 +  if (unlikely (!data))
   1.437 +    return NULL;
   1.438 +
   1.439 +  data->funcs = hb_uniscribe_shaper_get_funcs ();
   1.440 +  if (unlikely (!data->funcs))
   1.441 +  {
   1.442 +    free (data);
   1.443 +    return NULL;
   1.444 +  }
   1.445 +
   1.446 +  hb_blob_t *blob = hb_face_reference_blob (face);
   1.447 +  if (unlikely (!hb_blob_get_length (blob)))
   1.448 +    DEBUG_MSG (UNISCRIBE, face, "Face has empty blob");
   1.449 +
   1.450 +  blob = _hb_rename_font (blob, data->face_name);
   1.451 +  if (unlikely (!blob))
   1.452 +  {
   1.453 +    free (data);
   1.454 +    return NULL;
   1.455 +  }
   1.456 +
   1.457 +  DWORD num_fonts_installed;
   1.458 +  data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL),
   1.459 +				   hb_blob_get_length (blob),
   1.460 +				   0, &num_fonts_installed);
   1.461 +  if (unlikely (!data->fh))
   1.462 +  {
   1.463 +    DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
   1.464 +    free (data);
   1.465 +    return NULL;
   1.466 +  }
   1.467 +
   1.468 +  return data;
   1.469 +}
   1.470 +
   1.471 +void
   1.472 +_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
   1.473 +{
   1.474 +  RemoveFontMemResourceEx (data->fh);
   1.475 +  free (data);
   1.476 +}
   1.477 +
   1.478 +
   1.479 +/*
   1.480 + * shaper font data
   1.481 + */
   1.482 +
   1.483 +struct hb_uniscribe_shaper_font_data_t {
   1.484 +  HDC hdc;
   1.485 +  LOGFONTW log_font;
   1.486 +  HFONT hfont;
   1.487 +  SCRIPT_CACHE script_cache;
   1.488 +};
   1.489 +
   1.490 +static bool
   1.491 +populate_log_font (LOGFONTW  *lf,
   1.492 +		   hb_font_t *font)
   1.493 +{
   1.494 +  memset (lf, 0, sizeof (*lf));
   1.495 +  lf->lfHeight = -font->y_scale;
   1.496 +  lf->lfCharSet = DEFAULT_CHARSET;
   1.497 +
   1.498 +  hb_face_t *face = font->face;
   1.499 +  hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   1.500 +
   1.501 +  memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
   1.502 +
   1.503 +  return true;
   1.504 +}
   1.505 +
   1.506 +hb_uniscribe_shaper_font_data_t *
   1.507 +_hb_uniscribe_shaper_font_data_create (hb_font_t *font)
   1.508 +{
   1.509 +  if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL;
   1.510 +
   1.511 +  hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
   1.512 +  if (unlikely (!data))
   1.513 +    return NULL;
   1.514 +
   1.515 +  data->hdc = GetDC (NULL);
   1.516 +
   1.517 +  if (unlikely (!populate_log_font (&data->log_font, font))) {
   1.518 +    DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
   1.519 +    _hb_uniscribe_shaper_font_data_destroy (data);
   1.520 +    return NULL;
   1.521 +  }
   1.522 +
   1.523 +  data->hfont = CreateFontIndirectW (&data->log_font);
   1.524 +  if (unlikely (!data->hfont)) {
   1.525 +    DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
   1.526 +    _hb_uniscribe_shaper_font_data_destroy (data);
   1.527 +     return NULL;
   1.528 +  }
   1.529 +
   1.530 +  if (!SelectObject (data->hdc, data->hfont)) {
   1.531 +    DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
   1.532 +    _hb_uniscribe_shaper_font_data_destroy (data);
   1.533 +     return NULL;
   1.534 +  }
   1.535 +
   1.536 +  return data;
   1.537 +}
   1.538 +
   1.539 +void
   1.540 +_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
   1.541 +{
   1.542 +  if (data->hdc)
   1.543 +    ReleaseDC (NULL, data->hdc);
   1.544 +  if (data->hfont)
   1.545 +    DeleteObject (data->hfont);
   1.546 +  if (data->script_cache)
   1.547 +    ScriptFreeCache (&data->script_cache);
   1.548 +  free (data);
   1.549 +}
   1.550 +
   1.551 +LOGFONTW *
   1.552 +hb_uniscribe_font_get_logfontw (hb_font_t *font)
   1.553 +{
   1.554 +  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
   1.555 +  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   1.556 +  return &font_data->log_font;
   1.557 +}
   1.558 +
   1.559 +HFONT
   1.560 +hb_uniscribe_font_get_hfont (hb_font_t *font)
   1.561 +{
   1.562 +  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
   1.563 +  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
   1.564 +  return font_data->hfont;
   1.565 +}
   1.566 +
   1.567 +
   1.568 +/*
   1.569 + * shaper shape_plan data
   1.570 + */
   1.571 +
   1.572 +struct hb_uniscribe_shaper_shape_plan_data_t {};
   1.573 +
   1.574 +hb_uniscribe_shaper_shape_plan_data_t *
   1.575 +_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
   1.576 +					     const hb_feature_t *user_features HB_UNUSED,
   1.577 +					     unsigned int        num_user_features HB_UNUSED)
   1.578 +{
   1.579 +  return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
   1.580 +}
   1.581 +
   1.582 +void
   1.583 +_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
   1.584 +{
   1.585 +}
   1.586 +
   1.587 +
   1.588 +/*
   1.589 + * shaper
   1.590 + */
   1.591 +
   1.592 +
   1.593 +hb_bool_t
   1.594 +_hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
   1.595 +		     hb_font_t          *font,
   1.596 +		     hb_buffer_t        *buffer,
   1.597 +		     const hb_feature_t *features,
   1.598 +		     unsigned int        num_features)
   1.599 +{
   1.600 +  hb_face_t *face = font->face;
   1.601 +  hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
   1.602 +  hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
   1.603 +  hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
   1.604 +
   1.605 +  /*
   1.606 +   * Set up features.
   1.607 +   */
   1.608 +  hb_auto_array_t<OPENTYPE_FEATURE_RECORD> feature_records;
   1.609 +  hb_auto_array_t<range_record_t> range_records;
   1.610 +  if (num_features)
   1.611 +  {
   1.612 +    /* Sort features by start/end events. */
   1.613 +    hb_auto_array_t<feature_event_t> feature_events;
   1.614 +    for (unsigned int i = 0; i < num_features; i++)
   1.615 +    {
   1.616 +      active_feature_t feature;
   1.617 +      feature.rec.tagFeature = hb_uint32_swap (features[i].tag);
   1.618 +      feature.rec.lParameter = features[i].value;
   1.619 +      feature.order = i;
   1.620 +
   1.621 +      feature_event_t *event;
   1.622 +
   1.623 +      event = feature_events.push ();
   1.624 +      if (unlikely (!event))
   1.625 +	goto fail_features;
   1.626 +      event->index = features[i].start;
   1.627 +      event->start = true;
   1.628 +      event->feature = feature;
   1.629 +
   1.630 +      event = feature_events.push ();
   1.631 +      if (unlikely (!event))
   1.632 +	goto fail_features;
   1.633 +      event->index = features[i].end;
   1.634 +      event->start = false;
   1.635 +      event->feature = feature;
   1.636 +    }
   1.637 +    feature_events.sort ();
   1.638 +    /* Add a strategic final event. */
   1.639 +    {
   1.640 +      active_feature_t feature;
   1.641 +      feature.rec.tagFeature = 0;
   1.642 +      feature.rec.lParameter = 0;
   1.643 +      feature.order = num_features + 1;
   1.644 +
   1.645 +      feature_event_t *event = feature_events.push ();
   1.646 +      if (unlikely (!event))
   1.647 +	goto fail_features;
   1.648 +      event->index = 0; /* This value does magic. */
   1.649 +      event->start = false;
   1.650 +      event->feature = feature;
   1.651 +    }
   1.652 +
   1.653 +    /* Scan events and save features for each range. */
   1.654 +    hb_auto_array_t<active_feature_t> active_features;
   1.655 +    unsigned int last_index = 0;
   1.656 +    for (unsigned int i = 0; i < feature_events.len; i++)
   1.657 +    {
   1.658 +      feature_event_t *event = &feature_events[i];
   1.659 +
   1.660 +      if (event->index != last_index)
   1.661 +      {
   1.662 +        /* Save a snapshot of active features and the range. */
   1.663 +	range_record_t *range = range_records.push ();
   1.664 +	if (unlikely (!range))
   1.665 +	  goto fail_features;
   1.666 +
   1.667 +	unsigned int offset = feature_records.len;
   1.668 +
   1.669 +	active_features.sort ();
   1.670 +	for (unsigned int j = 0; j < active_features.len; j++)
   1.671 +	{
   1.672 +	  if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature)
   1.673 +	  {
   1.674 +	    OPENTYPE_FEATURE_RECORD *feature = feature_records.push ();
   1.675 +	    if (unlikely (!feature))
   1.676 +	      goto fail_features;
   1.677 +	    *feature = active_features[j].rec;
   1.678 +	  }
   1.679 +	  else
   1.680 +	  {
   1.681 +	    /* Overrides value for existing feature. */
   1.682 +	    feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter;
   1.683 +	  }
   1.684 +	}
   1.685 +
   1.686 +	/* Will convert to pointer after all is ready, since feature_records.array
   1.687 +	 * may move as we grow it. */
   1.688 +	range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
   1.689 +	range->props.cotfRecords = feature_records.len - offset;
   1.690 +	range->index_first = last_index;
   1.691 +	range->index_last  = event->index - 1;
   1.692 +
   1.693 +	last_index = event->index;
   1.694 +      }
   1.695 +
   1.696 +      if (event->start) {
   1.697 +        active_feature_t *feature = active_features.push ();
   1.698 +	if (unlikely (!feature))
   1.699 +	  goto fail_features;
   1.700 +	*feature = event->feature;
   1.701 +      } else {
   1.702 +        active_feature_t *feature = active_features.find (&event->feature);
   1.703 +	if (feature)
   1.704 +	  active_features.remove (feature - active_features.array);
   1.705 +      }
   1.706 +    }
   1.707 +
   1.708 +    if (!range_records.len) /* No active feature found. */
   1.709 +      goto fail_features;
   1.710 +
   1.711 +    /* Fixup the pointers. */
   1.712 +    for (unsigned int i = 0; i < range_records.len; i++)
   1.713 +    {
   1.714 +      range_record_t *range = &range_records[i];
   1.715 +      range->props.potfRecords = feature_records.array + reinterpret_cast<uintptr_t> (range->props.potfRecords);
   1.716 +    }
   1.717 +  }
   1.718 +  else
   1.719 +  {
   1.720 +  fail_features:
   1.721 +    num_features = 0;
   1.722 +  }
   1.723 +
   1.724 +#define FAIL(...) \
   1.725 +  HB_STMT_START { \
   1.726 +    DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
   1.727 +    return false; \
   1.728 +  } HB_STMT_END;
   1.729 +
   1.730 +  HRESULT hr;
   1.731 +
   1.732 +retry:
   1.733 +
   1.734 +  unsigned int scratch_size;
   1.735 +  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
   1.736 +
   1.737 +#define ALLOCATE_ARRAY(Type, name, len) \
   1.738 +  Type *name = (Type *) scratch; \
   1.739 +  { \
   1.740 +    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
   1.741 +    assert (_consumed <= scratch_size); \
   1.742 +    scratch += _consumed; \
   1.743 +    scratch_size -= _consumed; \
   1.744 +  }
   1.745 +
   1.746 +#define utf16_index() var1.u32
   1.747 +
   1.748 +  ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2);
   1.749 +
   1.750 +  unsigned int chars_len = 0;
   1.751 +  for (unsigned int i = 0; i < buffer->len; i++)
   1.752 +  {
   1.753 +    hb_codepoint_t c = buffer->info[i].codepoint;
   1.754 +    buffer->info[i].utf16_index() = chars_len;
   1.755 +    if (likely (c < 0x10000))
   1.756 +      pchars[chars_len++] = c;
   1.757 +    else if (unlikely (c >= 0x110000))
   1.758 +      pchars[chars_len++] = 0xFFFD;
   1.759 +    else {
   1.760 +      pchars[chars_len++] = 0xD800 + ((c - 0x10000) >> 10);
   1.761 +      pchars[chars_len++] = 0xDC00 + ((c - 0x10000) & ((1 << 10) - 1));
   1.762 +    }
   1.763 +  }
   1.764 +
   1.765 +  ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
   1.766 +  ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len);
   1.767 +
   1.768 +  if (num_features)
   1.769 +  {
   1.770 +    /* Need log_clusters to assign features. */
   1.771 +    chars_len = 0;
   1.772 +    for (unsigned int i = 0; i < buffer->len; i++)
   1.773 +    {
   1.774 +      hb_codepoint_t c = buffer->info[i].codepoint;
   1.775 +      unsigned int cluster = buffer->info[i].cluster;
   1.776 +      log_clusters[chars_len++] = cluster;
   1.777 +      if (c >= 0x10000 && c < 0x110000)
   1.778 +	log_clusters[chars_len++] = cluster; /* Surrogates. */
   1.779 +    }
   1.780 +  }
   1.781 +
   1.782 +  /* The -2 in the following is to compensate for possible
   1.783 +   * alignment needed after the WORD array.  sizeof(WORD) == 2. */
   1.784 +  unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
   1.785 +			   / (sizeof (WORD) +
   1.786 +			      sizeof (SCRIPT_GLYPHPROP) +
   1.787 +			      sizeof (int) +
   1.788 +			      sizeof (GOFFSET) +
   1.789 +			      sizeof (uint32_t));
   1.790 +
   1.791 +  ALLOCATE_ARRAY (WORD, glyphs, glyphs_size);
   1.792 +  ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size);
   1.793 +  ALLOCATE_ARRAY (int, advances, glyphs_size);
   1.794 +  ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size);
   1.795 +  ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
   1.796 +
   1.797 +  /* Note:
   1.798 +   * We can't touch the contents of glyph_props.  Our fallback
   1.799 +   * implementations of Shape and Place functions use that buffer
   1.800 +   * by casting it to a different type.  It works because they
   1.801 +   * both agree about it, but if we want to access it here we
   1.802 +   * need address that issue first.
   1.803 +   */
   1.804 +
   1.805 +#undef ALLOCATE_ARRAY
   1.806 +
   1.807 +#define MAX_ITEMS 256
   1.808 +
   1.809 +  SCRIPT_ITEM items[MAX_ITEMS + 1];
   1.810 +  SCRIPT_CONTROL bidi_control = {0};
   1.811 +  SCRIPT_STATE bidi_state = {0};
   1.812 +  ULONG script_tags[MAX_ITEMS];
   1.813 +  int item_count;
   1.814 +
   1.815 +  /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
   1.816 +  //bidi_control.fMergeNeutralItems = true;
   1.817 +  *(uint32_t*)&bidi_control |= 1<<24;
   1.818 +
   1.819 +  bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
   1.820 +  bidi_state.fOverrideDirection = 1;
   1.821 +
   1.822 +  hr = funcs->ScriptItemizeOpenType (pchars,
   1.823 +				     chars_len,
   1.824 +				     MAX_ITEMS,
   1.825 +				     &bidi_control,
   1.826 +				     &bidi_state,
   1.827 +				     items,
   1.828 +				     script_tags,
   1.829 +				     &item_count);
   1.830 +  if (unlikely (FAILED (hr)))
   1.831 +    FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr);
   1.832 +
   1.833 +#undef MAX_ITEMS
   1.834 +
   1.835 +  OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language));
   1.836 +  hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties;
   1.837 +  hb_auto_array_t<int> range_char_counts;
   1.838 +
   1.839 +  unsigned int glyphs_offset = 0;
   1.840 +  unsigned int glyphs_len;
   1.841 +  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
   1.842 +  for (unsigned int i = 0; i < item_count; i++)
   1.843 +  {
   1.844 +    unsigned int chars_offset = items[i].iCharPos;
   1.845 +    unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
   1.846 +
   1.847 +    if (num_features)
   1.848 +    {
   1.849 +      range_properties.shrink (0);
   1.850 +      range_char_counts.shrink (0);
   1.851 +
   1.852 +      range_record_t *last_range = &range_records[0];
   1.853 +
   1.854 +      for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++)
   1.855 +      {
   1.856 +	range_record_t *range = last_range;
   1.857 +	while (log_clusters[k] < range->index_first)
   1.858 +	  range--;
   1.859 +	while (log_clusters[k] > range->index_last)
   1.860 +	  range++;
   1.861 +	if (!range_properties.len ||
   1.862 +	    &range->props != range_properties[range_properties.len - 1])
   1.863 +	{
   1.864 +	  TEXTRANGE_PROPERTIES **props = range_properties.push ();
   1.865 +	  int *c = range_char_counts.push ();
   1.866 +	  if (unlikely (!props || !c))
   1.867 +	  {
   1.868 +	    range_properties.shrink (0);
   1.869 +	    range_char_counts.shrink (0);
   1.870 +	    break;
   1.871 +	  }
   1.872 +	  *props = &range->props;
   1.873 +	  *c = 1;
   1.874 +	}
   1.875 +	else
   1.876 +	{
   1.877 +	  range_char_counts[range_char_counts.len - 1]++;
   1.878 +	}
   1.879 +
   1.880 +	last_range = range;
   1.881 +      }
   1.882 +    }
   1.883 +
   1.884 +    /* Asking for glyphs in logical order circumvents at least
   1.885 +     * one bug in Uniscribe. */
   1.886 +    items[i].a.fLogicalOrder = true;
   1.887 +
   1.888 +  retry_shape:
   1.889 +    hr = funcs->ScriptShapeOpenType (font_data->hdc,
   1.890 +				     &font_data->script_cache,
   1.891 +				     &items[i].a,
   1.892 +				     script_tags[i],
   1.893 +				     language_tag,
   1.894 +				     range_char_counts.array,
   1.895 +				     range_properties.array,
   1.896 +				     range_properties.len,
   1.897 +				     pchars + chars_offset,
   1.898 +				     item_chars_len,
   1.899 +				     glyphs_size - glyphs_offset,
   1.900 +				     /* out */
   1.901 +				     log_clusters + chars_offset,
   1.902 +				     char_props + chars_offset,
   1.903 +				     glyphs + glyphs_offset,
   1.904 +				     glyph_props + glyphs_offset,
   1.905 +				     (int *) &glyphs_len);
   1.906 +
   1.907 +    if (unlikely (items[i].a.fNoGlyphIndex))
   1.908 +      FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
   1.909 +    if (unlikely (hr == E_OUTOFMEMORY))
   1.910 +    {
   1.911 +      buffer->ensure (buffer->allocated * 2);
   1.912 +      if (buffer->in_error)
   1.913 +	FAIL ("Buffer resize failed");
   1.914 +      goto retry;
   1.915 +    }
   1.916 +    if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
   1.917 +    {
   1.918 +      if (items[i].a.eScript == SCRIPT_UNDEFINED)
   1.919 +	FAIL ("ScriptShapeOpenType() failed: Font doesn't support script");
   1.920 +      items[i].a.eScript = SCRIPT_UNDEFINED;
   1.921 +      goto retry_shape;
   1.922 +    }
   1.923 +    if (unlikely (FAILED (hr)))
   1.924 +    {
   1.925 +      FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
   1.926 +    }
   1.927 +
   1.928 +    for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
   1.929 +      log_clusters[j] += glyphs_offset;
   1.930 +
   1.931 +    hr = funcs->ScriptPlaceOpenType (font_data->hdc,
   1.932 +				     &font_data->script_cache,
   1.933 +				     &items[i].a,
   1.934 +				     script_tags[i],
   1.935 +				     language_tag,
   1.936 +				     range_char_counts.array,
   1.937 +				     range_properties.array,
   1.938 +				     range_properties.len,
   1.939 +				     pchars + chars_offset,
   1.940 +				     log_clusters + chars_offset,
   1.941 +				     char_props + chars_offset,
   1.942 +				     item_chars_len,
   1.943 +				     glyphs + glyphs_offset,
   1.944 +				     glyph_props + glyphs_offset,
   1.945 +				     glyphs_len,
   1.946 +				     /* out */
   1.947 +				     advances + glyphs_offset,
   1.948 +				     offsets + glyphs_offset,
   1.949 +				     NULL);
   1.950 +    if (unlikely (FAILED (hr)))
   1.951 +      FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
   1.952 +
   1.953 +    if (DEBUG_ENABLED (UNISCRIBE))
   1.954 +      fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
   1.955 +	       i,
   1.956 +	       items[i].a.fRTL,
   1.957 +	       items[i].a.fLayoutRTL,
   1.958 +	       items[i].a.fLogicalOrder,
   1.959 +	       HB_UNTAG (hb_uint32_swap (script_tags[i])));
   1.960 +
   1.961 +    glyphs_offset += glyphs_len;
   1.962 +  }
   1.963 +  glyphs_len = glyphs_offset;
   1.964 +
   1.965 +  /* Ok, we've got everything we need, now compose output buffer,
   1.966 +   * very, *very*, carefully! */
   1.967 +
   1.968 +  /* Calculate visual-clusters.  That's what we ship. */
   1.969 +  for (unsigned int i = 0; i < glyphs_len; i++)
   1.970 +    vis_clusters[i] = -1;
   1.971 +  for (unsigned int i = 0; i < buffer->len; i++) {
   1.972 +    uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
   1.973 +    *p = MIN (*p, buffer->info[i].cluster);
   1.974 +  }
   1.975 +  for (unsigned int i = 1; i < glyphs_len; i++)
   1.976 +    if (vis_clusters[i] == -1)
   1.977 +      vis_clusters[i] = vis_clusters[i - 1];
   1.978 +
   1.979 +#undef utf16_index
   1.980 +
   1.981 +  buffer->ensure (glyphs_len);
   1.982 +  if (buffer->in_error)
   1.983 +    FAIL ("Buffer in error");
   1.984 +
   1.985 +#undef FAIL
   1.986 +
   1.987 +  /* Set glyph infos */
   1.988 +  buffer->len = 0;
   1.989 +  for (unsigned int i = 0; i < glyphs_len; i++)
   1.990 +  {
   1.991 +    hb_glyph_info_t *info = &buffer->info[buffer->len++];
   1.992 +
   1.993 +    info->codepoint = glyphs[i];
   1.994 +    info->cluster = vis_clusters[i];
   1.995 +
   1.996 +    /* The rest is crap.  Let's store position info there for now. */
   1.997 +    info->mask = advances[i];
   1.998 +    info->var1.u32 = offsets[i].du;
   1.999 +    info->var2.u32 = offsets[i].dv;
  1.1000 +  }
  1.1001 +
  1.1002 +  /* Set glyph positions */
  1.1003 +  buffer->clear_positions ();
  1.1004 +  for (unsigned int i = 0; i < glyphs_len; i++)
  1.1005 +  {
  1.1006 +    hb_glyph_info_t *info = &buffer->info[i];
  1.1007 +    hb_glyph_position_t *pos = &buffer->pos[i];
  1.1008 +
  1.1009 +    /* TODO vertical */
  1.1010 +    pos->x_advance = info->mask;
  1.1011 +    pos->x_offset = backward ? -info->var1.u32 : info->var1.u32;
  1.1012 +    pos->y_offset = info->var2.u32;
  1.1013 +  }
  1.1014 +
  1.1015 +  if (backward)
  1.1016 +    hb_buffer_reverse (buffer);
  1.1017 +
  1.1018 +  /* Wow, done! */
  1.1019 +  return true;
  1.1020 +}
  1.1021 +
  1.1022 +

mercurial