Blame src/hb-uniscribe.cc

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