Blame src/hb-uniscribe.cc

Packit Service 5bcba8
/*
Packit Service 5bcba8
 * Copyright © 2011,2012,2013  Google, Inc.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 *  This is part of HarfBuzz, a text shaping library.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * Permission is hereby granted, without written agreement and without
Packit Service 5bcba8
 * license or royalty fees, to use, copy, modify, and distribute this
Packit Service 5bcba8
 * software and its documentation for any purpose, provided that the
Packit Service 5bcba8
 * above copyright notice and the following two paragraphs appear in
Packit Service 5bcba8
 * all copies of this software.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
Packit Service 5bcba8
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
Packit Service 5bcba8
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
Packit Service 5bcba8
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
Packit Service 5bcba8
 * DAMAGE.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
Packit Service 5bcba8
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
Packit Service 5bcba8
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
Packit Service 5bcba8
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
Packit Service 5bcba8
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
Packit Service 5bcba8
 *
Packit Service 5bcba8
 * Google Author(s): Behdad Esfahbod
Packit Service 5bcba8
 */
Packit Service 5bcba8
Packit Service 5bcba8
#define HB_SHAPER uniscribe
Packit Service 5bcba8
#include "hb-shaper-impl-private.hh"
Packit Service 5bcba8
Packit Service 5bcba8
#include <windows.h>
Packit Service 5bcba8
#include <usp10.h>
Packit Service 5bcba8
#include <rpc.h>
Packit Service 5bcba8
Packit Service 5bcba8
#include "hb-uniscribe.h"
Packit Service 5bcba8
Packit Service 5bcba8
#include "hb-open-file-private.hh"
Packit Service 5bcba8
#include "hb-ot-name-table.hh"
Packit Service 5bcba8
#include "hb-ot-tag.h"
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
#ifndef HB_DEBUG_UNISCRIBE
Packit Service 5bcba8
#define HB_DEBUG_UNISCRIBE (HB_DEBUG+0)
Packit Service 5bcba8
#endif
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
static inline uint16_t hb_uint16_swap (const uint16_t v)
Packit Service 5bcba8
{ return (v >> 8) | (v << 8); }
Packit Service 5bcba8
static inline uint32_t hb_uint32_swap (const uint32_t v)
Packit Service 5bcba8
{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
Packit Service 5bcba8
  const WCHAR *pwcInChars,
Packit Service 5bcba8
  int cInChars,
Packit Service 5bcba8
  int cMaxItems,
Packit Service 5bcba8
  const SCRIPT_CONTROL *psControl,
Packit Service 5bcba8
  const SCRIPT_STATE *psState,
Packit Service 5bcba8
  SCRIPT_ITEM *pItems,
Packit Service 5bcba8
  OPENTYPE_TAG *pScriptTags,
Packit Service 5bcba8
  int *pcItems
Packit Service 5bcba8
);
Packit Service 5bcba8
Packit Service 5bcba8
typedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/(
Packit Service 5bcba8
  HDC hdc,
Packit Service 5bcba8
  SCRIPT_CACHE *psc,
Packit Service 5bcba8
  SCRIPT_ANALYSIS *psa,
Packit Service 5bcba8
  OPENTYPE_TAG tagScript,
Packit Service 5bcba8
  OPENTYPE_TAG tagLangSys,
Packit Service 5bcba8
  int *rcRangeChars,
Packit Service 5bcba8
  TEXTRANGE_PROPERTIES **rpRangeProperties,
Packit Service 5bcba8
  int cRanges,
Packit Service 5bcba8
  const WCHAR *pwcChars,
Packit Service 5bcba8
  int cChars,
Packit Service 5bcba8
  int cMaxGlyphs,
Packit Service 5bcba8
  WORD *pwLogClust,
Packit Service 5bcba8
  SCRIPT_CHARPROP *pCharProps,
Packit Service 5bcba8
  WORD *pwOutGlyphs,
Packit Service 5bcba8
  SCRIPT_GLYPHPROP *pOutGlyphProps,
Packit Service 5bcba8
  int *pcGlyphs
Packit Service 5bcba8
);
Packit Service 5bcba8
Packit Service 5bcba8
typedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/(
Packit Service 5bcba8
  HDC hdc,
Packit Service 5bcba8
  SCRIPT_CACHE *psc,
Packit Service 5bcba8
  SCRIPT_ANALYSIS *psa,
Packit Service 5bcba8
  OPENTYPE_TAG tagScript,
Packit Service 5bcba8
  OPENTYPE_TAG tagLangSys,
Packit Service 5bcba8
  int *rcRangeChars,
Packit Service 5bcba8
  TEXTRANGE_PROPERTIES **rpRangeProperties,
Packit Service 5bcba8
  int cRanges,
Packit Service 5bcba8
  const WCHAR *pwcChars,
Packit Service 5bcba8
  WORD *pwLogClust,
Packit Service 5bcba8
  SCRIPT_CHARPROP *pCharProps,
Packit Service 5bcba8
  int cChars,
Packit Service 5bcba8
  const WORD *pwGlyphs,
Packit Service 5bcba8
  const SCRIPT_GLYPHPROP *pGlyphProps,
Packit Service 5bcba8
  int cGlyphs,
Packit Service 5bcba8
  int *piAdvance,
Packit Service 5bcba8
  GOFFSET *pGoffset,
Packit Service 5bcba8
  ABC *pABC
Packit Service 5bcba8
);
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
/* Fallback implementations. */
Packit Service 5bcba8
Packit Service 5bcba8
static HRESULT WINAPI
Packit Service 5bcba8
hb_ScriptItemizeOpenType(
Packit Service 5bcba8
  const WCHAR *pwcInChars,
Packit Service 5bcba8
  int cInChars,
Packit Service 5bcba8
  int cMaxItems,
Packit Service 5bcba8
  const SCRIPT_CONTROL *psControl,
Packit Service 5bcba8
  const SCRIPT_STATE *psState,
Packit Service 5bcba8
  SCRIPT_ITEM *pItems,
Packit Service 5bcba8
  OPENTYPE_TAG *pScriptTags,
Packit Service 5bcba8
  int *pcItems
Packit Service 5bcba8
)
Packit Service 5bcba8
{
Packit Service 5bcba8
{
Packit Service 5bcba8
  return ScriptItemize (pwcInChars,
Packit Service 5bcba8
			cInChars,
Packit Service 5bcba8
			cMaxItems,
Packit Service 5bcba8
			psControl,
Packit Service 5bcba8
			psState,
Packit Service 5bcba8
			pItems,
Packit Service 5bcba8
			pcItems);
Packit Service 5bcba8
}
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static HRESULT WINAPI
Packit Service 5bcba8
hb_ScriptShapeOpenType(
Packit Service 5bcba8
  HDC hdc,
Packit Service 5bcba8
  SCRIPT_CACHE *psc,
Packit Service 5bcba8
  SCRIPT_ANALYSIS *psa,
Packit Service 5bcba8
  OPENTYPE_TAG tagScript,
Packit Service 5bcba8
  OPENTYPE_TAG tagLangSys,
Packit Service 5bcba8
  int *rcRangeChars,
Packit Service 5bcba8
  TEXTRANGE_PROPERTIES **rpRangeProperties,
Packit Service 5bcba8
  int cRanges,
Packit Service 5bcba8
  const WCHAR *pwcChars,
Packit Service 5bcba8
  int cChars,
Packit Service 5bcba8
  int cMaxGlyphs,
Packit Service 5bcba8
  WORD *pwLogClust,
Packit Service 5bcba8
  SCRIPT_CHARPROP *pCharProps,
Packit Service 5bcba8
  WORD *pwOutGlyphs,
Packit Service 5bcba8
  SCRIPT_GLYPHPROP *pOutGlyphProps,
Packit Service 5bcba8
  int *pcGlyphs
Packit Service 5bcba8
)
Packit Service 5bcba8
{
Packit Service 5bcba8
  SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps;
Packit Service 5bcba8
  return ScriptShape (hdc,
Packit Service 5bcba8
		      psc,
Packit Service 5bcba8
		      pwcChars,
Packit Service 5bcba8
		      cChars,
Packit Service 5bcba8
		      cMaxGlyphs,
Packit Service 5bcba8
		      psa,
Packit Service 5bcba8
		      pwOutGlyphs,
Packit Service 5bcba8
		      pwLogClust,
Packit Service 5bcba8
		      psva,
Packit Service 5bcba8
		      pcGlyphs);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static HRESULT WINAPI
Packit Service 5bcba8
hb_ScriptPlaceOpenType(
Packit Service 5bcba8
  HDC hdc,
Packit Service 5bcba8
  SCRIPT_CACHE *psc,
Packit Service 5bcba8
  SCRIPT_ANALYSIS *psa,
Packit Service 5bcba8
  OPENTYPE_TAG tagScript,
Packit Service 5bcba8
  OPENTYPE_TAG tagLangSys,
Packit Service 5bcba8
  int *rcRangeChars,
Packit Service 5bcba8
  TEXTRANGE_PROPERTIES **rpRangeProperties,
Packit Service 5bcba8
  int cRanges,
Packit Service 5bcba8
  const WCHAR *pwcChars,
Packit Service 5bcba8
  WORD *pwLogClust,
Packit Service 5bcba8
  SCRIPT_CHARPROP *pCharProps,
Packit Service 5bcba8
  int cChars,
Packit Service 5bcba8
  const WORD *pwGlyphs,
Packit Service 5bcba8
  const SCRIPT_GLYPHPROP *pGlyphProps,
Packit Service 5bcba8
  int cGlyphs,
Packit Service 5bcba8
  int *piAdvance,
Packit Service 5bcba8
  GOFFSET *pGoffset,
Packit Service 5bcba8
  ABC *pABC
Packit Service 5bcba8
)
Packit Service 5bcba8
{
Packit Service 5bcba8
  SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pGlyphProps;
Packit Service 5bcba8
  return ScriptPlace (hdc,
Packit Service 5bcba8
		      psc,
Packit Service 5bcba8
		      pwGlyphs,
Packit Service 5bcba8
		      cGlyphs,
Packit Service 5bcba8
		      psva,
Packit Service 5bcba8
		      psa,
Packit Service 5bcba8
		      piAdvance,
Packit Service 5bcba8
		      pGoffset,
Packit Service 5bcba8
		      pABC);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
struct hb_uniscribe_shaper_funcs_t {
Packit Service 5bcba8
  SIOT ScriptItemizeOpenType;
Packit Service 5bcba8
  SSOT ScriptShapeOpenType;
Packit Service 5bcba8
  SPOT ScriptPlaceOpenType;
Packit Service 5bcba8
Packit Service 5bcba8
  inline void init (void)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    HMODULE hinstLib;
Packit Service 5bcba8
    this->ScriptItemizeOpenType = NULL;
Packit Service 5bcba8
    this->ScriptShapeOpenType   = NULL;
Packit Service 5bcba8
    this->ScriptPlaceOpenType   = NULL;
Packit Service 5bcba8
Packit Service 5bcba8
    hinstLib = GetModuleHandle (TEXT ("usp10.dll"));
Packit Service 5bcba8
    if (hinstLib)
Packit Service 5bcba8
    {
Packit Service 5bcba8
      this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType");
Packit Service 5bcba8
      this->ScriptShapeOpenType   = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType");
Packit Service 5bcba8
      this->ScriptPlaceOpenType   = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType");
Packit Service 5bcba8
    }
Packit Service 5bcba8
    if (!this->ScriptItemizeOpenType ||
Packit Service 5bcba8
	!this->ScriptShapeOpenType   ||
Packit Service 5bcba8
	!this->ScriptPlaceOpenType)
Packit Service 5bcba8
    {
Packit Service 5bcba8
      DEBUG_MSG (UNISCRIBE, NULL, "OpenType versions of functions not found; falling back.");
Packit Service 5bcba8
      this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType;
Packit Service 5bcba8
      this->ScriptShapeOpenType   = hb_ScriptShapeOpenType;
Packit Service 5bcba8
      this->ScriptPlaceOpenType   = hb_ScriptPlaceOpenType;
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
};
Packit Service 5bcba8
static hb_uniscribe_shaper_funcs_t *uniscribe_funcs;
Packit Service 5bcba8
Packit Service 5bcba8
static inline void
Packit Service 5bcba8
free_uniscribe_funcs (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
  free (uniscribe_funcs);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
static hb_uniscribe_shaper_funcs_t *
Packit Service 5bcba8
hb_uniscribe_shaper_get_funcs (void)
Packit Service 5bcba8
{
Packit Service 5bcba8
retry:
Packit Service 5bcba8
  hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs);
Packit Service 5bcba8
Packit Service 5bcba8
  if (unlikely (!funcs))
Packit Service 5bcba8
  {
Packit Service 5bcba8
    funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
Packit Service 5bcba8
    if (unlikely (!funcs))
Packit Service 5bcba8
      return NULL;
Packit Service 5bcba8
Packit Service 5bcba8
    funcs->init ();
Packit Service 5bcba8
Packit Service 5bcba8
    if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, NULL, funcs)) {
Packit Service 5bcba8
      free (funcs);
Packit Service 5bcba8
      goto retry;
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
#ifdef HB_USE_ATEXIT
Packit Service 5bcba8
    atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
Packit Service 5bcba8
#endif
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  return funcs;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
struct active_feature_t {
Packit Service 5bcba8
  OPENTYPE_FEATURE_RECORD rec;
Packit Service 5bcba8
  unsigned int order;
Packit Service 5bcba8
Packit Service 5bcba8
  static int cmp (const active_feature_t *a, const active_feature_t *b) {
Packit Service 5bcba8
    return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 :
Packit Service 5bcba8
	   a->order < b->order ? -1 : a->order > b->order ? 1 :
Packit Service 5bcba8
	   a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 :
Packit Service 5bcba8
	   0;
Packit Service 5bcba8
  }
Packit Service 5bcba8
  bool operator== (const active_feature_t *f) {
Packit Service 5bcba8
    return cmp (this, f) == 0;
Packit Service 5bcba8
  }
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct feature_event_t {
Packit Service 5bcba8
  unsigned int index;
Packit Service 5bcba8
  bool start;
Packit Service 5bcba8
  active_feature_t feature;
Packit Service 5bcba8
Packit Service 5bcba8
  static int cmp (const feature_event_t *a, const feature_event_t *b) {
Packit Service 5bcba8
    return a->index < b->index ? -1 : a->index > b->index ? 1 :
Packit Service 5bcba8
	   a->start < b->start ? -1 : a->start > b->start ? 1 :
Packit Service 5bcba8
	   active_feature_t::cmp (&a->feature, &b->feature);
Packit Service 5bcba8
  }
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
struct range_record_t {
Packit Service 5bcba8
  TEXTRANGE_PROPERTIES props;
Packit Service 5bcba8
  unsigned int index_first; /* == start */
Packit Service 5bcba8
  unsigned int index_last;  /* == end - 1 */
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, face)
Packit Service 5bcba8
HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, font)
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
/*
Packit Service 5bcba8
 * shaper face data
Packit Service 5bcba8
 */
Packit Service 5bcba8
Packit Service 5bcba8
struct hb_uniscribe_shaper_face_data_t {
Packit Service 5bcba8
  HANDLE fh;
Packit Service 5bcba8
  hb_uniscribe_shaper_funcs_t *funcs;
Packit Service 5bcba8
  wchar_t face_name[LF_FACESIZE];
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
/* face_name should point to a wchar_t[LF_FACESIZE] object. */
Packit Service 5bcba8
static void
Packit Service 5bcba8
_hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen)
Packit Service 5bcba8
{
Packit Service 5bcba8
  /* We'll create a private name for the font from a UUID using a simple,
Packit Service 5bcba8
   * somewhat base64-like encoding scheme */
Packit Service 5bcba8
  const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
Packit Service 5bcba8
  UUID id;
Packit Service 5bcba8
  UuidCreate ((UUID*) &id;;
Packit Service 5bcba8
  ASSERT_STATIC (2 + 3 * (16/2) < LF_FACESIZE);
Packit Service 5bcba8
  unsigned int name_str_len = 0;
Packit Service 5bcba8
  face_name[name_str_len++] = 'F';
Packit Service 5bcba8
  face_name[name_str_len++] = '_';
Packit Service 5bcba8
  unsigned char *p = (unsigned char *) &id;
Packit Service 5bcba8
  for (unsigned int i = 0; i < 16; i += 2)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
Packit Service 5bcba8
     * using the bits in groups of 5,5,6 to select chars from enc.
Packit Service 5bcba8
     * This will generate 24 characters; with the 'F_' prefix we already provided,
Packit Service 5bcba8
     * the name will be 26 chars (plus the NUL terminator), so will always fit within
Packit Service 5bcba8
     * face_name (LF_FACESIZE = 32). */
Packit Service 5bcba8
    face_name[name_str_len++] = enc[p[i] >> 3];
Packit Service 5bcba8
    face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
Packit Service 5bcba8
    face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
Packit Service 5bcba8
  }
Packit Service 5bcba8
  face_name[name_str_len] = 0;
Packit Service 5bcba8
  if (plen)
Packit Service 5bcba8
    *plen = name_str_len;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
/* Destroys blob. */
Packit Service 5bcba8
static hb_blob_t *
Packit Service 5bcba8
_hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
Packit Service 5bcba8
{
Packit Service 5bcba8
  /* Create a copy of the font data, with the 'name' table replaced by a
Packit Service 5bcba8
   * table that names the font with our private F_* name created above.
Packit Service 5bcba8
   * For simplicity, we just append a new 'name' table and update the
Packit Service 5bcba8
   * sfnt directory; the original table is left in place, but unused.
Packit Service 5bcba8
   *
Packit Service 5bcba8
   * The new table will contain just 5 name IDs: family, style, unique,
Packit Service 5bcba8
   * full, PS. All of them point to the same name data with our unique name.
Packit Service 5bcba8
   */
Packit Service 5bcba8
Packit Service 5bcba8
  blob = OT::Sanitizer<OT::OpenTypeFontFile>::sanitize (blob);
Packit Service 5bcba8
Packit Service 5bcba8
  unsigned int length, new_length, name_str_len;
Packit Service 5bcba8
  const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
Packit Service 5bcba8
Packit Service 5bcba8
  _hb_generate_unique_face_name (new_name, &name_str_len);
Packit Service 5bcba8
Packit Service 5bcba8
  static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };
Packit Service 5bcba8
Packit Service 5bcba8
  unsigned int name_table_length = OT::name::min_size +
Packit Service 5bcba8
                                   ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size +
Packit Service 5bcba8
                                   name_str_len * 2; /* for name data in UTF16BE form */
Packit Service 5bcba8
  unsigned int name_table_offset = (length + 3) & ~3;
Packit Service 5bcba8
Packit Service 5bcba8
  new_length = name_table_offset + ((name_table_length + 3) & ~3);
Packit Service 5bcba8
  void *new_sfnt_data = calloc (1, new_length);
Packit Service 5bcba8
  if (!new_sfnt_data)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    hb_blob_destroy (blob);
Packit Service 5bcba8
    return NULL;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  memcpy(new_sfnt_data, orig_sfnt_data, length);
Packit Service 5bcba8
Packit Service 5bcba8
  OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
Packit Service 5bcba8
  name.format.set (0);
Packit Service 5bcba8
  name.count.set (ARRAY_LENGTH (name_IDs));
Packit Service 5bcba8
  name.stringOffset.set (name.get_size ());
Packit Service 5bcba8
  for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    OT::NameRecord &record = name.nameRecord[i];
Packit Service 5bcba8
    record.platformID.set (3);
Packit Service 5bcba8
    record.encodingID.set (1);
Packit Service 5bcba8
    record.languageID.set (0x0409u); /* English */
Packit Service 5bcba8
    record.nameID.set (name_IDs[i]);
Packit Service 5bcba8
    record.length.set (name_str_len * 2);
Packit Service 5bcba8
    record.offset.set (0);
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  /* Copy string data from new_name, converting wchar_t to UTF16BE. */
Packit Service 5bcba8
  unsigned char *p = &OT::StructAfter<unsigned char> (name);
Packit Service 5bcba8
  for (unsigned int i = 0; i < name_str_len; i++)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    *p++ = new_name[i] >> 8;
Packit Service 5bcba8
    *p++ = new_name[i] & 0xff;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  /* Adjust name table entry to point to new name table */
Packit Service 5bcba8
  const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data);
Packit Service 5bcba8
  unsigned int face_count = file.get_face_count ();
Packit Service 5bcba8
  for (unsigned int face_index = 0; face_index < face_count; face_index++)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    /* Note: doing multiple edits (ie. TTC) can be unsafe.  There may be
Packit Service 5bcba8
     * toe-stepping.  But we don't really care. */
Packit Service 5bcba8
    const OT::OpenTypeFontFace &face = file.get_face (face_index);
Packit Service 5bcba8
    unsigned int index;
Packit Service 5bcba8
    if (face.find_table_index (HB_OT_TAG_name, &index))
Packit Service 5bcba8
    {
Packit Service 5bcba8
      OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
Packit Service 5bcba8
      record.checkSum.set_for_data (&name, name_table_length);
Packit Service 5bcba8
      record.offset.set (name_table_offset);
Packit Service 5bcba8
      record.length.set (name_table_length);
Packit Service 5bcba8
    }
Packit Service 5bcba8
    else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
Packit Service 5bcba8
    {
Packit Service 5bcba8
      free (new_sfnt_data);
Packit Service 5bcba8
      hb_blob_destroy (blob);
Packit Service 5bcba8
      return NULL;
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  /* The checkSumAdjustment field in the 'head' table is now wrong,
Packit Service 5bcba8
   * but that doesn't actually seem to cause any problems so we don't
Packit Service 5bcba8
   * bother. */
Packit Service 5bcba8
Packit Service 5bcba8
  hb_blob_destroy (blob);
Packit Service 5bcba8
  return hb_blob_create ((const char *) new_sfnt_data, new_length,
Packit Service 5bcba8
			 HB_MEMORY_MODE_WRITABLE, NULL, free);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
hb_uniscribe_shaper_face_data_t *
Packit Service 5bcba8
_hb_uniscribe_shaper_face_data_create (hb_face_t *face)
Packit Service 5bcba8
{
Packit Service 5bcba8
  hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
Packit Service 5bcba8
  if (unlikely (!data))
Packit Service 5bcba8
    return NULL;
Packit Service 5bcba8
Packit Service 5bcba8
  data->funcs = hb_uniscribe_shaper_get_funcs ();
Packit Service 5bcba8
  if (unlikely (!data->funcs))
Packit Service 5bcba8
  {
Packit Service 5bcba8
    free (data);
Packit Service 5bcba8
    return NULL;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  hb_blob_t *blob = hb_face_reference_blob (face);
Packit Service 5bcba8
  if (unlikely (!hb_blob_get_length (blob)))
Packit Service 5bcba8
    DEBUG_MSG (UNISCRIBE, face, "Face has empty blob");
Packit Service 5bcba8
Packit Service 5bcba8
  blob = _hb_rename_font (blob, data->face_name);
Packit Service 5bcba8
  if (unlikely (!blob))
Packit Service 5bcba8
  {
Packit Service 5bcba8
    free (data);
Packit Service 5bcba8
    return NULL;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  DWORD num_fonts_installed;
Packit Service 5bcba8
  data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, NULL),
Packit Service 5bcba8
				   hb_blob_get_length (blob),
Packit Service 5bcba8
				   0, &num_fonts_installed);
Packit Service 5bcba8
  if (unlikely (!data->fh))
Packit Service 5bcba8
  {
Packit Service 5bcba8
    DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
Packit Service 5bcba8
    free (data);
Packit Service 5bcba8
    return NULL;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  return data;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
void
Packit Service 5bcba8
_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
Packit Service 5bcba8
{
Packit Service 5bcba8
  RemoveFontMemResourceEx (data->fh);
Packit Service 5bcba8
  free (data);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
/*
Packit Service 5bcba8
 * shaper font data
Packit Service 5bcba8
 */
Packit Service 5bcba8
Packit Service 5bcba8
struct hb_uniscribe_shaper_font_data_t {
Packit Service 5bcba8
  HDC hdc;
Packit Service 5bcba8
  LOGFONTW log_font;
Packit Service 5bcba8
  HFONT hfont;
Packit Service 5bcba8
  SCRIPT_CACHE script_cache;
Packit Service 5bcba8
  double x_mult, y_mult; /* From LOGFONT space to HB space. */
Packit Service 5bcba8
};
Packit Service 5bcba8
Packit Service 5bcba8
static bool
Packit Service 5bcba8
populate_log_font (LOGFONTW  *lf,
Packit Service 5bcba8
		   hb_font_t *font,
Packit Service 5bcba8
		   unsigned int font_size)
Packit Service 5bcba8
{
Packit Service 5bcba8
  memset (lf, 0, sizeof (*lf));
Packit Service 5bcba8
  lf->lfHeight = -font_size;
Packit Service 5bcba8
  lf->lfCharSet = DEFAULT_CHARSET;
Packit Service 5bcba8
Packit Service 5bcba8
  hb_face_t *face = font->face;
Packit Service 5bcba8
  hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
Packit Service 5bcba8
Packit Service 5bcba8
  memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
Packit Service 5bcba8
Packit Service 5bcba8
  return true;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
hb_uniscribe_shaper_font_data_t *
Packit Service 5bcba8
_hb_uniscribe_shaper_font_data_create (hb_font_t *font)
Packit Service 5bcba8
{
Packit Service 5bcba8
  if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return NULL;
Packit Service 5bcba8
Packit Service 5bcba8
  hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
Packit Service 5bcba8
  if (unlikely (!data))
Packit Service 5bcba8
    return NULL;
Packit Service 5bcba8
Packit Service 5bcba8
  int font_size = font->face->get_upem (); /* Default... */
Packit Service 5bcba8
  /* No idea if the following is even a good idea. */
Packit Service 5bcba8
  if (font->y_ppem)
Packit Service 5bcba8
    font_size = font->y_ppem;
Packit Service 5bcba8
Packit Service 5bcba8
  if (font_size < 0)
Packit Service 5bcba8
    font_size = -font_size;
Packit Service 5bcba8
  data->x_mult = (double) font->x_scale / font_size;
Packit Service 5bcba8
  data->y_mult = (double) font->y_scale / font_size;
Packit Service 5bcba8
Packit Service 5bcba8
  data->hdc = GetDC (NULL);
Packit Service 5bcba8
Packit Service 5bcba8
  if (unlikely (!populate_log_font (&data->log_font, font, font_size))) {
Packit Service 5bcba8
    DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
Packit Service 5bcba8
    _hb_uniscribe_shaper_font_data_destroy (data);
Packit Service 5bcba8
    return NULL;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  data->hfont = CreateFontIndirectW (&data->log_font);
Packit Service 5bcba8
  if (unlikely (!data->hfont)) {
Packit Service 5bcba8
    DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
Packit Service 5bcba8
    _hb_uniscribe_shaper_font_data_destroy (data);
Packit Service 5bcba8
     return NULL;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  if (!SelectObject (data->hdc, data->hfont)) {
Packit Service 5bcba8
    DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
Packit Service 5bcba8
    _hb_uniscribe_shaper_font_data_destroy (data);
Packit Service 5bcba8
     return NULL;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  return data;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
void
Packit Service 5bcba8
_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
Packit Service 5bcba8
{
Packit Service 5bcba8
  if (data->hdc)
Packit Service 5bcba8
    ReleaseDC (NULL, data->hdc);
Packit Service 5bcba8
  if (data->hfont)
Packit Service 5bcba8
    DeleteObject (data->hfont);
Packit Service 5bcba8
  if (data->script_cache)
Packit Service 5bcba8
    ScriptFreeCache (&data->script_cache);
Packit Service 5bcba8
  free (data);
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
LOGFONTW *
Packit Service 5bcba8
hb_uniscribe_font_get_logfontw (hb_font_t *font)
Packit Service 5bcba8
{
Packit Service 5bcba8
  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
Packit Service 5bcba8
  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
Packit Service 5bcba8
  return &font_data->log_font;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
HFONT
Packit Service 5bcba8
hb_uniscribe_font_get_hfont (hb_font_t *font)
Packit Service 5bcba8
{
Packit Service 5bcba8
  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return NULL;
Packit Service 5bcba8
  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
Packit Service 5bcba8
  return font_data->hfont;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
/*
Packit Service 5bcba8
 * shaper shape_plan data
Packit Service 5bcba8
 */
Packit Service 5bcba8
Packit Service 5bcba8
struct hb_uniscribe_shaper_shape_plan_data_t {};
Packit Service 5bcba8
Packit Service 5bcba8
hb_uniscribe_shaper_shape_plan_data_t *
Packit Service 5bcba8
_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
Packit Service 5bcba8
					     const hb_feature_t *user_features HB_UNUSED,
Packit Service 5bcba8
					     unsigned int        num_user_features HB_UNUSED,
Packit Service 5bcba8
					     const int          *coords HB_UNUSED,
Packit Service 5bcba8
					     unsigned int        num_coords HB_UNUSED)
Packit Service 5bcba8
{
Packit Service 5bcba8
  return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
void
Packit Service 5bcba8
_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
Packit Service 5bcba8
{
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
/*
Packit Service 5bcba8
 * shaper
Packit Service 5bcba8
 */
Packit Service 5bcba8
Packit Service 5bcba8
Packit Service 5bcba8
hb_bool_t
Packit Service 5bcba8
_hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
Packit Service 5bcba8
		     hb_font_t          *font,
Packit Service 5bcba8
		     hb_buffer_t        *buffer,
Packit Service 5bcba8
		     const hb_feature_t *features,
Packit Service 5bcba8
		     unsigned int        num_features)
Packit Service 5bcba8
{
Packit Service 5bcba8
  hb_face_t *face = font->face;
Packit Service 5bcba8
  hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
Packit Service 5bcba8
  hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
Packit Service 5bcba8
  hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
Packit Service 5bcba8
Packit Service 5bcba8
  /*
Packit Service 5bcba8
   * Set up features.
Packit Service 5bcba8
   */
Packit Service 5bcba8
  hb_auto_array_t<OPENTYPE_FEATURE_RECORD> feature_records;
Packit Service 5bcba8
  hb_auto_array_t<range_record_t> range_records;
Packit Service 5bcba8
  if (num_features)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    /* Sort features by start/end events. */
Packit Service 5bcba8
    hb_auto_array_t<feature_event_t> feature_events;
Packit Service 5bcba8
    for (unsigned int i = 0; i < num_features; i++)
Packit Service 5bcba8
    {
Packit Service 5bcba8
      active_feature_t feature;
Packit Service 5bcba8
      feature.rec.tagFeature = hb_uint32_swap (features[i].tag);
Packit Service 5bcba8
      feature.rec.lParameter = features[i].value;
Packit Service 5bcba8
      feature.order = i;
Packit Service 5bcba8
Packit Service 5bcba8
      feature_event_t *event;
Packit Service 5bcba8
Packit Service 5bcba8
      event = feature_events.push ();
Packit Service 5bcba8
      if (unlikely (!event))
Packit Service 5bcba8
	goto fail_features;
Packit Service 5bcba8
      event->index = features[i].start;
Packit Service 5bcba8
      event->start = true;
Packit Service 5bcba8
      event->feature = feature;
Packit Service 5bcba8
Packit Service 5bcba8
      event = feature_events.push ();
Packit Service 5bcba8
      if (unlikely (!event))
Packit Service 5bcba8
	goto fail_features;
Packit Service 5bcba8
      event->index = features[i].end;
Packit Service 5bcba8
      event->start = false;
Packit Service 5bcba8
      event->feature = feature;
Packit Service 5bcba8
    }
Packit Service 5bcba8
    feature_events.qsort ();
Packit Service 5bcba8
    /* Add a strategic final event. */
Packit Service 5bcba8
    {
Packit Service 5bcba8
      active_feature_t feature;
Packit Service 5bcba8
      feature.rec.tagFeature = 0;
Packit Service 5bcba8
      feature.rec.lParameter = 0;
Packit Service 5bcba8
      feature.order = num_features + 1;
Packit Service 5bcba8
Packit Service 5bcba8
      feature_event_t *event = feature_events.push ();
Packit Service 5bcba8
      if (unlikely (!event))
Packit Service 5bcba8
	goto fail_features;
Packit Service 5bcba8
      event->index = 0; /* This value does magic. */
Packit Service 5bcba8
      event->start = false;
Packit Service 5bcba8
      event->feature = feature;
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    /* Scan events and save features for each range. */
Packit Service 5bcba8
    hb_auto_array_t<active_feature_t> active_features;
Packit Service 5bcba8
    unsigned int last_index = 0;
Packit Service 5bcba8
    for (unsigned int i = 0; i < feature_events.len; i++)
Packit Service 5bcba8
    {
Packit Service 5bcba8
      feature_event_t *event = &feature_events[i];
Packit Service 5bcba8
Packit Service 5bcba8
      if (event->index != last_index)
Packit Service 5bcba8
      {
Packit Service 5bcba8
        /* Save a snapshot of active features and the range. */
Packit Service 5bcba8
	range_record_t *range = range_records.push ();
Packit Service 5bcba8
	if (unlikely (!range))
Packit Service 5bcba8
	  goto fail_features;
Packit Service 5bcba8
Packit Service 5bcba8
	unsigned int offset = feature_records.len;
Packit Service 5bcba8
Packit Service 5bcba8
	active_features.qsort ();
Packit Service 5bcba8
	for (unsigned int j = 0; j < active_features.len; j++)
Packit Service 5bcba8
	{
Packit Service 5bcba8
	  if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature)
Packit Service 5bcba8
	  {
Packit Service 5bcba8
	    OPENTYPE_FEATURE_RECORD *feature = feature_records.push ();
Packit Service 5bcba8
	    if (unlikely (!feature))
Packit Service 5bcba8
	      goto fail_features;
Packit Service 5bcba8
	    *feature = active_features[j].rec;
Packit Service 5bcba8
	  }
Packit Service 5bcba8
	  else
Packit Service 5bcba8
	  {
Packit Service 5bcba8
	    /* Overrides value for existing feature. */
Packit Service 5bcba8
	    feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter;
Packit Service 5bcba8
	  }
Packit Service 5bcba8
	}
Packit Service 5bcba8
Packit Service 5bcba8
	/* Will convert to pointer after all is ready, since feature_records.array
Packit Service 5bcba8
	 * may move as we grow it. */
Packit Service 5bcba8
	range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
Packit Service 5bcba8
	range->props.cotfRecords = feature_records.len - offset;
Packit Service 5bcba8
	range->index_first = last_index;
Packit Service 5bcba8
	range->index_last  = event->index - 1;
Packit Service 5bcba8
Packit Service 5bcba8
	last_index = event->index;
Packit Service 5bcba8
      }
Packit Service 5bcba8
Packit Service 5bcba8
      if (event->start) {
Packit Service 5bcba8
        active_feature_t *feature = active_features.push ();
Packit Service 5bcba8
	if (unlikely (!feature))
Packit Service 5bcba8
	  goto fail_features;
Packit Service 5bcba8
	*feature = event->feature;
Packit Service 5bcba8
      } else {
Packit Service 5bcba8
        active_feature_t *feature = active_features.find (&event->feature);
Packit Service 5bcba8
	if (feature)
Packit Service 5bcba8
	  active_features.remove (feature - active_features.array);
Packit Service 5bcba8
      }
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    if (!range_records.len) /* No active feature found. */
Packit Service 5bcba8
      goto fail_features;
Packit Service 5bcba8
Packit Service 5bcba8
    /* Fixup the pointers. */
Packit Service 5bcba8
    for (unsigned int i = 0; i < range_records.len; i++)
Packit Service 5bcba8
    {
Packit Service 5bcba8
      range_record_t *range = &range_records[i];
Packit Service 5bcba8
      range->props.potfRecords = feature_records.array + reinterpret_cast<uintptr_t> (range->props.potfRecords);
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
  else
Packit Service 5bcba8
  {
Packit Service 5bcba8
  fail_features:
Packit Service 5bcba8
    num_features = 0;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
#define FAIL(...) \
Packit Service 5bcba8
  HB_STMT_START { \
Packit Service 5bcba8
    DEBUG_MSG (UNISCRIBE, NULL, __VA_ARGS__); \
Packit Service 5bcba8
    return false; \
Packit Service 5bcba8
  } HB_STMT_END;
Packit Service 5bcba8
Packit Service 5bcba8
  HRESULT hr;
Packit Service 5bcba8
Packit Service 5bcba8
retry:
Packit Service 5bcba8
Packit Service 5bcba8
  unsigned int scratch_size;
Packit Service 5bcba8
  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
Packit Service 5bcba8
Packit Service 5bcba8
#define ALLOCATE_ARRAY(Type, name, len) \
Packit Service 5bcba8
  Type *name = (Type *) scratch; \
Packit Service 5bcba8
  { \
Packit Service 5bcba8
    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
Packit Service 5bcba8
    assert (_consumed <= scratch_size); \
Packit Service 5bcba8
    scratch += _consumed; \
Packit Service 5bcba8
    scratch_size -= _consumed; \
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
#define utf16_index() var1.u32
Packit Service 5bcba8
Packit Service 5bcba8
  ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2);
Packit Service 5bcba8
Packit Service 5bcba8
  unsigned int chars_len = 0;
Packit Service 5bcba8
  for (unsigned int i = 0; i < buffer->len; i++)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    hb_codepoint_t c = buffer->info[i].codepoint;
Packit Service 5bcba8
    buffer->info[i].utf16_index() = chars_len;
Packit Service 5bcba8
    if (likely (c <= 0xFFFFu))
Packit Service 5bcba8
      pchars[chars_len++] = c;
Packit Service 5bcba8
    else if (unlikely (c > 0x10FFFFu))
Packit Service 5bcba8
      pchars[chars_len++] = 0xFFFDu;
Packit Service 5bcba8
    else {
Packit Service 5bcba8
      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
Packit Service 5bcba8
      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
Packit Service 5bcba8
  ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len);
Packit Service 5bcba8
Packit Service 5bcba8
  if (num_features)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    /* Need log_clusters to assign features. */
Packit Service 5bcba8
    chars_len = 0;
Packit Service 5bcba8
    for (unsigned int i = 0; i < buffer->len; i++)
Packit Service 5bcba8
    {
Packit Service 5bcba8
      hb_codepoint_t c = buffer->info[i].codepoint;
Packit Service 5bcba8
      unsigned int cluster = buffer->info[i].cluster;
Packit Service 5bcba8
      log_clusters[chars_len++] = cluster;
Packit Service 5bcba8
      if (hb_in_range (c, 0x10000u, 0x10FFFFu))
Packit Service 5bcba8
	log_clusters[chars_len++] = cluster; /* Surrogates. */
Packit Service 5bcba8
    }
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  /* The -2 in the following is to compensate for possible
Packit Service 5bcba8
   * alignment needed after the WORD array.  sizeof(WORD) == 2. */
Packit Service 5bcba8
  unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
Packit Service 5bcba8
			   / (sizeof (WORD) +
Packit Service 5bcba8
			      sizeof (SCRIPT_GLYPHPROP) +
Packit Service 5bcba8
			      sizeof (int) +
Packit Service 5bcba8
			      sizeof (GOFFSET) +
Packit Service 5bcba8
			      sizeof (uint32_t));
Packit Service 5bcba8
Packit Service 5bcba8
  ALLOCATE_ARRAY (WORD, glyphs, glyphs_size);
Packit Service 5bcba8
  ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size);
Packit Service 5bcba8
  ALLOCATE_ARRAY (int, advances, glyphs_size);
Packit Service 5bcba8
  ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size);
Packit Service 5bcba8
  ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);
Packit Service 5bcba8
Packit Service 5bcba8
  /* Note:
Packit Service 5bcba8
   * We can't touch the contents of glyph_props.  Our fallback
Packit Service 5bcba8
   * implementations of Shape and Place functions use that buffer
Packit Service 5bcba8
   * by casting it to a different type.  It works because they
Packit Service 5bcba8
   * both agree about it, but if we want to access it here we
Packit Service 5bcba8
   * need address that issue first.
Packit Service 5bcba8
   */
Packit Service 5bcba8
Packit Service 5bcba8
#undef ALLOCATE_ARRAY
Packit Service 5bcba8
Packit Service 5bcba8
#define MAX_ITEMS 256
Packit Service 5bcba8
Packit Service 5bcba8
  SCRIPT_ITEM items[MAX_ITEMS + 1];
Packit Service 5bcba8
  SCRIPT_CONTROL bidi_control = {0};
Packit Service 5bcba8
  SCRIPT_STATE bidi_state = {0};
Packit Service 5bcba8
  ULONG script_tags[MAX_ITEMS];
Packit Service 5bcba8
  int item_count;
Packit Service 5bcba8
Packit Service 5bcba8
  /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
Packit Service 5bcba8
  //bidi_control.fMergeNeutralItems = true;
Packit Service 5bcba8
  *(uint32_t*)&bidi_control |= 1u<<24;
Packit Service 5bcba8
Packit Service 5bcba8
  bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
Packit Service 5bcba8
  bidi_state.fOverrideDirection = 1;
Packit Service 5bcba8
Packit Service 5bcba8
  hr = funcs->ScriptItemizeOpenType (pchars,
Packit Service 5bcba8
				     chars_len,
Packit Service 5bcba8
				     MAX_ITEMS,
Packit Service 5bcba8
				     &bidi_control,
Packit Service 5bcba8
				     &bidi_state,
Packit Service 5bcba8
				     items,
Packit Service 5bcba8
				     script_tags,
Packit Service 5bcba8
				     &item_count);
Packit Service 5bcba8
  if (unlikely (FAILED (hr)))
Packit Service 5bcba8
    FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr);
Packit Service 5bcba8
Packit Service 5bcba8
#undef MAX_ITEMS
Packit Service 5bcba8
Packit Service 5bcba8
  OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language));
Packit Service 5bcba8
  hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties;
Packit Service 5bcba8
  hb_auto_array_t<int> range_char_counts;
Packit Service 5bcba8
Packit Service 5bcba8
  unsigned int glyphs_offset = 0;
Packit Service 5bcba8
  unsigned int glyphs_len;
Packit Service 5bcba8
  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
Packit Service 5bcba8
  for (unsigned int i = 0; i < item_count; i++)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    unsigned int chars_offset = items[i].iCharPos;
Packit Service 5bcba8
    unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;
Packit Service 5bcba8
Packit Service 5bcba8
    if (num_features)
Packit Service 5bcba8
    {
Packit Service 5bcba8
      range_properties.shrink (0);
Packit Service 5bcba8
      range_char_counts.shrink (0);
Packit Service 5bcba8
Packit Service 5bcba8
      range_record_t *last_range = &range_records[0];
Packit Service 5bcba8
Packit Service 5bcba8
      for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++)
Packit Service 5bcba8
      {
Packit Service 5bcba8
	range_record_t *range = last_range;
Packit Service 5bcba8
	while (log_clusters[k] < range->index_first)
Packit Service 5bcba8
	  range--;
Packit Service 5bcba8
	while (log_clusters[k] > range->index_last)
Packit Service 5bcba8
	  range++;
Packit Service 5bcba8
	if (!range_properties.len ||
Packit Service 5bcba8
	    &range->props != range_properties[range_properties.len - 1])
Packit Service 5bcba8
	{
Packit Service 5bcba8
	  TEXTRANGE_PROPERTIES **props = range_properties.push ();
Packit Service 5bcba8
	  int *c = range_char_counts.push ();
Packit Service 5bcba8
	  if (unlikely (!props || !c))
Packit Service 5bcba8
	  {
Packit Service 5bcba8
	    range_properties.shrink (0);
Packit Service 5bcba8
	    range_char_counts.shrink (0);
Packit Service 5bcba8
	    break;
Packit Service 5bcba8
	  }
Packit Service 5bcba8
	  *props = &range->props;
Packit Service 5bcba8
	  *c = 1;
Packit Service 5bcba8
	}
Packit Service 5bcba8
	else
Packit Service 5bcba8
	{
Packit Service 5bcba8
	  range_char_counts[range_char_counts.len - 1]++;
Packit Service 5bcba8
	}
Packit Service 5bcba8
Packit Service 5bcba8
	last_range = range;
Packit Service 5bcba8
      }
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    /* Asking for glyphs in logical order circumvents at least
Packit Service 5bcba8
     * one bug in Uniscribe. */
Packit Service 5bcba8
    items[i].a.fLogicalOrder = true;
Packit Service 5bcba8
Packit Service 5bcba8
  retry_shape:
Packit Service 5bcba8
    hr = funcs->ScriptShapeOpenType (font_data->hdc,
Packit Service 5bcba8
				     &font_data->script_cache,
Packit Service 5bcba8
				     &items[i].a,
Packit Service 5bcba8
				     script_tags[i],
Packit Service 5bcba8
				     language_tag,
Packit Service 5bcba8
				     range_char_counts.array,
Packit Service 5bcba8
				     range_properties.array,
Packit Service 5bcba8
				     range_properties.len,
Packit Service 5bcba8
				     pchars + chars_offset,
Packit Service 5bcba8
				     item_chars_len,
Packit Service 5bcba8
				     glyphs_size - glyphs_offset,
Packit Service 5bcba8
				     /* out */
Packit Service 5bcba8
				     log_clusters + chars_offset,
Packit Service 5bcba8
				     char_props + chars_offset,
Packit Service 5bcba8
				     glyphs + glyphs_offset,
Packit Service 5bcba8
				     glyph_props + glyphs_offset,
Packit Service 5bcba8
				     (int *) &glyphs_len);
Packit Service 5bcba8
Packit Service 5bcba8
    if (unlikely (items[i].a.fNoGlyphIndex))
Packit Service 5bcba8
      FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
Packit Service 5bcba8
    if (unlikely (hr == E_OUTOFMEMORY || hr == E_NOT_SUFFICIENT_BUFFER))
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (unlikely (!buffer->ensure (buffer->allocated * 2)))
Packit Service 5bcba8
	FAIL ("Buffer resize failed");
Packit Service 5bcba8
      goto retry;
Packit Service 5bcba8
    }
Packit Service 5bcba8
    if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
Packit Service 5bcba8
    {
Packit Service 5bcba8
      if (items[i].a.eScript == SCRIPT_UNDEFINED)
Packit Service 5bcba8
	FAIL ("ScriptShapeOpenType() failed: Font doesn't support script");
Packit Service 5bcba8
      items[i].a.eScript = SCRIPT_UNDEFINED;
Packit Service 5bcba8
      goto retry_shape;
Packit Service 5bcba8
    }
Packit Service 5bcba8
    if (unlikely (FAILED (hr)))
Packit Service 5bcba8
    {
Packit Service 5bcba8
      FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
Packit Service 5bcba8
    }
Packit Service 5bcba8
Packit Service 5bcba8
    for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
Packit Service 5bcba8
      log_clusters[j] += glyphs_offset;
Packit Service 5bcba8
Packit Service 5bcba8
    hr = funcs->ScriptPlaceOpenType (font_data->hdc,
Packit Service 5bcba8
				     &font_data->script_cache,
Packit Service 5bcba8
				     &items[i].a,
Packit Service 5bcba8
				     script_tags[i],
Packit Service 5bcba8
				     language_tag,
Packit Service 5bcba8
				     range_char_counts.array,
Packit Service 5bcba8
				     range_properties.array,
Packit Service 5bcba8
				     range_properties.len,
Packit Service 5bcba8
				     pchars + chars_offset,
Packit Service 5bcba8
				     log_clusters + chars_offset,
Packit Service 5bcba8
				     char_props + chars_offset,
Packit Service 5bcba8
				     item_chars_len,
Packit Service 5bcba8
				     glyphs + glyphs_offset,
Packit Service 5bcba8
				     glyph_props + glyphs_offset,
Packit Service 5bcba8
				     glyphs_len,
Packit Service 5bcba8
				     /* out */
Packit Service 5bcba8
				     advances + glyphs_offset,
Packit Service 5bcba8
				     offsets + glyphs_offset,
Packit Service 5bcba8
				     NULL);
Packit Service 5bcba8
    if (unlikely (FAILED (hr)))
Packit Service 5bcba8
      FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);
Packit Service 5bcba8
Packit Service 5bcba8
    if (DEBUG_ENABLED (UNISCRIBE))
Packit Service 5bcba8
      fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
Packit Service 5bcba8
	       i,
Packit Service 5bcba8
	       items[i].a.fRTL,
Packit Service 5bcba8
	       items[i].a.fLayoutRTL,
Packit Service 5bcba8
	       items[i].a.fLogicalOrder,
Packit Service 5bcba8
	       HB_UNTAG (hb_uint32_swap (script_tags[i])));
Packit Service 5bcba8
Packit Service 5bcba8
    glyphs_offset += glyphs_len;
Packit Service 5bcba8
  }
Packit Service 5bcba8
  glyphs_len = glyphs_offset;
Packit Service 5bcba8
Packit Service 5bcba8
  /* Ok, we've got everything we need, now compose output buffer,
Packit Service 5bcba8
   * very, *very*, carefully! */
Packit Service 5bcba8
Packit Service 5bcba8
  /* Calculate visual-clusters.  That's what we ship. */
Packit Service 5bcba8
  for (unsigned int i = 0; i < glyphs_len; i++)
Packit Service 5bcba8
    vis_clusters[i] = -1;
Packit Service 5bcba8
  for (unsigned int i = 0; i < buffer->len; i++) {
Packit Service 5bcba8
    uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
Packit Service 5bcba8
    *p = MIN (*p, buffer->info[i].cluster);
Packit Service 5bcba8
  }
Packit Service 5bcba8
  for (unsigned int i = 1; i < glyphs_len; i++)
Packit Service 5bcba8
    if (vis_clusters[i] == -1)
Packit Service 5bcba8
      vis_clusters[i] = vis_clusters[i - 1];
Packit Service 5bcba8
Packit Service 5bcba8
#undef utf16_index
Packit Service 5bcba8
Packit Service 5bcba8
  if (unlikely (!buffer->ensure (glyphs_len)))
Packit Service 5bcba8
    FAIL ("Buffer in error");
Packit Service 5bcba8
Packit Service 5bcba8
#undef FAIL
Packit Service 5bcba8
Packit Service 5bcba8
  /* Set glyph infos */
Packit Service 5bcba8
  buffer->len = 0;
Packit Service 5bcba8
  for (unsigned int i = 0; i < glyphs_len; i++)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    hb_glyph_info_t *info = &buffer->info[buffer->len++];
Packit Service 5bcba8
Packit Service 5bcba8
    info->codepoint = glyphs[i];
Packit Service 5bcba8
    info->cluster = vis_clusters[i];
Packit Service 5bcba8
Packit Service 5bcba8
    /* The rest is crap.  Let's store position info there for now. */
Packit Service 5bcba8
    info->mask = advances[i];
Packit Service 5bcba8
    info->var1.i32 = offsets[i].du;
Packit Service 5bcba8
    info->var2.i32 = offsets[i].dv;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  /* Set glyph positions */
Packit Service 5bcba8
  buffer->clear_positions ();
Packit Service 5bcba8
  double x_mult = font_data->x_mult, y_mult = font_data->y_mult;
Packit Service 5bcba8
  for (unsigned int i = 0; i < glyphs_len; i++)
Packit Service 5bcba8
  {
Packit Service 5bcba8
    hb_glyph_info_t *info = &buffer->info[i];
Packit Service 5bcba8
    hb_glyph_position_t *pos = &buffer->pos[i];
Packit Service 5bcba8
Packit Service 5bcba8
    /* TODO vertical */
Packit Service 5bcba8
    pos->x_advance = x_mult * (int32_t) info->mask;
Packit Service 5bcba8
    pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32);
Packit Service 5bcba8
    pos->y_offset = y_mult * info->var2.i32;
Packit Service 5bcba8
  }
Packit Service 5bcba8
Packit Service 5bcba8
  if (backward)
Packit Service 5bcba8
    hb_buffer_reverse (buffer);
Packit Service 5bcba8
Packit Service 5bcba8
  /* Wow, done! */
Packit Service 5bcba8
  return true;
Packit Service 5bcba8
}
Packit Service 5bcba8
Packit Service 5bcba8