hb-uniscribe.cc 29.1 KB
Newer Older
1
/*
2
 * Copyright © 2011,2012,2013  Google, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 *  This is part of HarfBuzz, a text shaping library.
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Google Author(s): Behdad Esfahbod
 */

27 28
#include "hb-private.hh"
#include "hb-debug.hh"
29 30
#define HB_SHAPER uniscribe
#include "hb-shaper-impl-private.hh"
31

32 33
#include <windows.h>
#include <usp10.h>
34
#include <rpc.h>
35

36 37
#include "hb-uniscribe.h"

38
#include "hb-open-file-private.hh"
39
#include "hb-ot-name-table.hh"
40 41 42
#include "hb-ot-tag.h"


B
Behdad Esfahbod 已提交
43 44 45 46 47 48
static inline uint16_t hb_uint16_swap (const uint16_t v)
{ return (v >> 8) | (v << 8); }
static inline uint32_t hb_uint32_swap (const uint32_t v)
{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); }


49
typedef HRESULT (WINAPI *SIOT) /*ScriptItemizeOpenType*/(
50 51 52 53 54 55 56 57 58 59
  const WCHAR *pwcInChars,
  int cInChars,
  int cMaxItems,
  const SCRIPT_CONTROL *psControl,
  const SCRIPT_STATE *psState,
  SCRIPT_ITEM *pItems,
  OPENTYPE_TAG *pScriptTags,
  int *pcItems
);

60
typedef HRESULT (WINAPI *SSOT) /*ScriptShapeOpenType*/(
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
  HDC hdc,
  SCRIPT_CACHE *psc,
  SCRIPT_ANALYSIS *psa,
  OPENTYPE_TAG tagScript,
  OPENTYPE_TAG tagLangSys,
  int *rcRangeChars,
  TEXTRANGE_PROPERTIES **rpRangeProperties,
  int cRanges,
  const WCHAR *pwcChars,
  int cChars,
  int cMaxGlyphs,
  WORD *pwLogClust,
  SCRIPT_CHARPROP *pCharProps,
  WORD *pwOutGlyphs,
  SCRIPT_GLYPHPROP *pOutGlyphProps,
  int *pcGlyphs
77
);
78

79
typedef HRESULT (WINAPI *SPOT) /*ScriptPlaceOpenType*/(
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
  HDC hdc,
  SCRIPT_CACHE *psc,
  SCRIPT_ANALYSIS *psa,
  OPENTYPE_TAG tagScript,
  OPENTYPE_TAG tagLangSys,
  int *rcRangeChars,
  TEXTRANGE_PROPERTIES **rpRangeProperties,
  int cRanges,
  const WCHAR *pwcChars,
  WORD *pwLogClust,
  SCRIPT_CHARPROP *pCharProps,
  int cChars,
  const WORD *pwGlyphs,
  const SCRIPT_GLYPHPROP *pGlyphProps,
  int cGlyphs,
  int *piAdvance,
  GOFFSET *pGoffset,
  ABC *pABC
);


/* Fallback implementations. */

static HRESULT WINAPI
hb_ScriptItemizeOpenType(
  const WCHAR *pwcInChars,
  int cInChars,
  int cMaxItems,
  const SCRIPT_CONTROL *psControl,
  const SCRIPT_STATE *psState,
  SCRIPT_ITEM *pItems,
  OPENTYPE_TAG *pScriptTags,
  int *pcItems
)
{
{
  return ScriptItemize (pwcInChars,
			cInChars,
			cMaxItems,
			psControl,
			psState,
			pItems,
			pcItems);
}
}

static HRESULT WINAPI
hb_ScriptShapeOpenType(
  HDC hdc,
  SCRIPT_CACHE *psc,
  SCRIPT_ANALYSIS *psa,
  OPENTYPE_TAG tagScript,
  OPENTYPE_TAG tagLangSys,
  int *rcRangeChars,
  TEXTRANGE_PROPERTIES **rpRangeProperties,
  int cRanges,
  const WCHAR *pwcChars,
  int cChars,
  int cMaxGlyphs,
  WORD *pwLogClust,
  SCRIPT_CHARPROP *pCharProps,
  WORD *pwOutGlyphs,
  SCRIPT_GLYPHPROP *pOutGlyphProps,
  int *pcGlyphs
)
{
  SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pOutGlyphProps;
  return ScriptShape (hdc,
		      psc,
		      pwcChars,
		      cChars,
		      cMaxGlyphs,
		      psa,
		      pwOutGlyphs,
		      pwLogClust,
		      psva,
		      pcGlyphs);
}

static HRESULT WINAPI
hb_ScriptPlaceOpenType(
  HDC hdc,
  SCRIPT_CACHE *psc,
  SCRIPT_ANALYSIS *psa,
  OPENTYPE_TAG tagScript,
  OPENTYPE_TAG tagLangSys,
  int *rcRangeChars,
  TEXTRANGE_PROPERTIES **rpRangeProperties,
  int cRanges,
  const WCHAR *pwcChars,
  WORD *pwLogClust,
  SCRIPT_CHARPROP *pCharProps,
  int cChars,
  const WORD *pwGlyphs,
  const SCRIPT_GLYPHPROP *pGlyphProps,
  int cGlyphs,
  int *piAdvance,
  GOFFSET *pGoffset,
  ABC *pABC
)
{
  SCRIPT_VISATTR *psva = (SCRIPT_VISATTR *) pGlyphProps;
  return ScriptPlace (hdc,
		      psc,
		      pwGlyphs,
		      cGlyphs,
		      psva,
		      psa,
		      piAdvance,
		      pGoffset,
		      pABC);
}


struct hb_uniscribe_shaper_funcs_t {
  SIOT ScriptItemizeOpenType;
  SSOT ScriptShapeOpenType;
  SPOT ScriptPlaceOpenType;

  inline void init (void)
  {
201
    HMODULE hinstLib;
B
Behdad Esfahbod 已提交
202 203 204
    this->ScriptItemizeOpenType = nullptr;
    this->ScriptShapeOpenType   = nullptr;
    this->ScriptPlaceOpenType   = nullptr;
205

206
    hinstLib = GetModuleHandle (TEXT ("usp10.dll"));
207 208 209 210 211 212 213 214 215 216
    if (hinstLib)
    {
      this->ScriptItemizeOpenType = (SIOT) GetProcAddress (hinstLib, "ScriptItemizeOpenType");
      this->ScriptShapeOpenType   = (SSOT) GetProcAddress (hinstLib, "ScriptShapeOpenType");
      this->ScriptPlaceOpenType   = (SPOT) GetProcAddress (hinstLib, "ScriptPlaceOpenType");
    }
    if (!this->ScriptItemizeOpenType ||
	!this->ScriptShapeOpenType   ||
	!this->ScriptPlaceOpenType)
    {
B
Behdad Esfahbod 已提交
217
      DEBUG_MSG (UNISCRIBE, nullptr, "OpenType versions of functions not found; falling back.");
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
      this->ScriptItemizeOpenType = hb_ScriptItemizeOpenType;
      this->ScriptShapeOpenType   = hb_ScriptShapeOpenType;
      this->ScriptPlaceOpenType   = hb_ScriptPlaceOpenType;
    }
  }
};
static hb_uniscribe_shaper_funcs_t *uniscribe_funcs;

static inline void
free_uniscribe_funcs (void)
{
  free (uniscribe_funcs);
}

static hb_uniscribe_shaper_funcs_t *
hb_uniscribe_shaper_get_funcs (void)
{
retry:
  hb_uniscribe_shaper_funcs_t *funcs = (hb_uniscribe_shaper_funcs_t *) hb_atomic_ptr_get (&uniscribe_funcs);

  if (unlikely (!funcs))
  {
    funcs = (hb_uniscribe_shaper_funcs_t *) calloc (1, sizeof (hb_uniscribe_shaper_funcs_t));
    if (unlikely (!funcs))
B
Behdad Esfahbod 已提交
242
      return nullptr;
243 244 245

    funcs->init ();

B
Behdad Esfahbod 已提交
246
    if (!hb_atomic_ptr_cmpexch (&uniscribe_funcs, nullptr, funcs)) {
247 248 249 250
      free (funcs);
      goto retry;
    }

251
#ifdef HB_USE_ATEXIT
252 253 254 255 256 257
    atexit (free_uniscribe_funcs); /* First person registers atexit() callback. */
#endif
  }

  return funcs;
}
258

B
Behdad Esfahbod 已提交
259

260 261 262 263
struct active_feature_t {
  OPENTYPE_FEATURE_RECORD rec;
  unsigned int order;

B
Behdad Esfahbod 已提交
264 265 266
  static int cmp (const void *pa, const void *pb) {
    const active_feature_t *a = (const active_feature_t *) pa;
    const active_feature_t *b = (const active_feature_t *) pb;
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
    return a->rec.tagFeature < b->rec.tagFeature ? -1 : a->rec.tagFeature > b->rec.tagFeature ? 1 :
	   a->order < b->order ? -1 : a->order > b->order ? 1 :
	   a->rec.lParameter < b->rec.lParameter ? -1 : a->rec.lParameter > b->rec.lParameter ? 1 :
	   0;
  }
  bool operator== (const active_feature_t *f) {
    return cmp (this, f) == 0;
  }
};

struct feature_event_t {
  unsigned int index;
  bool start;
  active_feature_t feature;

B
Behdad Esfahbod 已提交
282 283 284
  static int cmp (const void *pa, const void *pb) {
    const feature_event_t *a = (const feature_event_t *) pa;
    const feature_event_t *b = (const feature_event_t *) pb;
285 286 287 288 289 290 291 292 293 294 295 296
    return a->index < b->index ? -1 : a->index > b->index ? 1 :
	   a->start < b->start ? -1 : a->start > b->start ? 1 :
	   active_feature_t::cmp (&a->feature, &b->feature);
  }
};

struct range_record_t {
  TEXTRANGE_PROPERTIES props;
  unsigned int index_first; /* == start */
  unsigned int index_last;  /* == end - 1 */
};

B
Behdad Esfahbod 已提交
297 298
HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, face)
HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, font)
299 300


301 302 303
/*
 * shaper face data
 */
B
Behdad Esfahbod 已提交
304

305
struct hb_uniscribe_shaper_face_data_t {
B
Behdad Esfahbod 已提交
306
  HANDLE fh;
307
  hb_uniscribe_shaper_funcs_t *funcs;
308
  wchar_t face_name[LF_FACESIZE];
309
};
B
Behdad Esfahbod 已提交
310

311 312 313
/* face_name should point to a wchar_t[LF_FACESIZE] object. */
static void
_hb_generate_unique_face_name (wchar_t *face_name, unsigned int *plen)
314 315 316 317 318 319
{
  /* We'll create a private name for the font from a UUID using a simple,
   * somewhat base64-like encoding scheme */
  const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
  UUID id;
  UuidCreate ((UUID*) &id);
320
  static_assert ((2 + 3 * (16/2) < LF_FACESIZE), "");
321
  unsigned int name_str_len = 0;
322 323
  face_name[name_str_len++] = 'F';
  face_name[name_str_len++] = '_';
324 325 326 327 328 329 330 331
  unsigned char *p = (unsigned char *) &id;
  for (unsigned int i = 0; i < 16; i += 2)
  {
    /* Spread the 16 bits from two bytes of the UUID across three chars of face_name,
     * using the bits in groups of 5,5,6 to select chars from enc.
     * This will generate 24 characters; with the 'F_' prefix we already provided,
     * the name will be 26 chars (plus the NUL terminator), so will always fit within
     * face_name (LF_FACESIZE = 32). */
332 333 334
    face_name[name_str_len++] = enc[p[i] >> 3];
    face_name[name_str_len++] = enc[((p[i] << 2) | (p[i + 1] >> 6)) & 0x1f];
    face_name[name_str_len++] = enc[p[i + 1] & 0x3f];
335
  }
336 337 338 339 340 341 342 343 344
  face_name[name_str_len] = 0;
  if (plen)
    *plen = name_str_len;
}

/* Destroys blob. */
static hb_blob_t *
_hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
{
B
Behdad Esfahbod 已提交
345 346 347 348 349 350 351 352 353
  /* Create a copy of the font data, with the 'name' table replaced by a
   * table that names the font with our private F_* name created above.
   * For simplicity, we just append a new 'name' table and update the
   * sfnt directory; the original table is left in place, but unused.
   *
   * The new table will contain just 5 name IDs: family, style, unique,
   * full, PS. All of them point to the same name data with our unique name.
   */

B
Behdad Esfahbod 已提交
354
  blob = OT::Sanitizer<OT::OpenTypeFontFile>().sanitize (blob);
B
Behdad Esfahbod 已提交
355

356 357 358 359
  unsigned int length, new_length, name_str_len;
  const char *orig_sfnt_data = hb_blob_get_data (blob, &length);

  _hb_generate_unique_face_name (new_name, &name_str_len);
360 361 362

  static const uint16_t name_IDs[] = { 1, 2, 3, 4, 6 };

B
Behdad Esfahbod 已提交
363 364
  unsigned int name_table_length = OT::name::min_size +
                                   ARRAY_LENGTH (name_IDs) * OT::NameRecord::static_size +
365
                                   name_str_len * 2; /* for name data in UTF16BE form */
366
  unsigned int padded_name_table_length = ((name_table_length + 3) & ~3);
367 368
  unsigned int name_table_offset = (length + 3) & ~3;

369
  new_length = name_table_offset + padded_name_table_length;
B
Behdad Esfahbod 已提交
370
  void *new_sfnt_data = calloc (1, new_length);
371
  if (!new_sfnt_data)
B
Behdad Esfahbod 已提交
372 373
  {
    hb_blob_destroy (blob);
B
Behdad Esfahbod 已提交
374
    return nullptr;
B
Behdad Esfahbod 已提交
375
  }
376 377 378

  memcpy(new_sfnt_data, orig_sfnt_data, length);

B
Behdad Esfahbod 已提交
379 380 381 382 383 384 385 386 387
  OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
  name.format.set (0);
  name.count.set (ARRAY_LENGTH (name_IDs));
  name.stringOffset.set (name.get_size ());
  for (unsigned int i = 0; i < ARRAY_LENGTH (name_IDs); i++)
  {
    OT::NameRecord &record = name.nameRecord[i];
    record.platformID.set (3);
    record.encodingID.set (1);
388
    record.languageID.set (0x0409u); /* English */
B
Behdad Esfahbod 已提交
389 390 391
    record.nameID.set (name_IDs[i]);
    record.length.set (name_str_len * 2);
    record.offset.set (0);
392 393
  }

B
Behdad Esfahbod 已提交
394 395 396 397
  /* Copy string data from new_name, converting wchar_t to UTF16BE. */
  unsigned char *p = &OT::StructAfter<unsigned char> (name);
  for (unsigned int i = 0; i < name_str_len; i++)
  {
398 399 400 401
    *p++ = new_name[i] >> 8;
    *p++ = new_name[i] & 0xff;
  }

B
Behdad Esfahbod 已提交
402
  /* Adjust name table entry to point to new name table */
403 404 405
  const OT::OpenTypeFontFile &file = * (OT::OpenTypeFontFile *) (new_sfnt_data);
  unsigned int face_count = file.get_face_count ();
  for (unsigned int face_index = 0; face_index < face_count; face_index++)
406
  {
B
Behdad Esfahbod 已提交
407 408
    /* Note: doing multiple edits (ie. TTC) can be unsafe.  There may be
     * toe-stepping.  But we don't really care. */
409 410 411 412 413
    const OT::OpenTypeFontFace &face = file.get_face (face_index);
    unsigned int index;
    if (face.find_table_index (HB_OT_TAG_name, &index))
    {
      OT::TableRecord &record = const_cast<OT::TableRecord &> (face.get_table (index));
414
      record.checkSum.set_for_data (&name, padded_name_table_length);
415 416 417 418 419 420 421
      record.offset.set (name_table_offset);
      record.length.set (name_table_length);
    }
    else if (face_index == 0) /* Fail if first face doesn't have 'name' table. */
    {
      free (new_sfnt_data);
      hb_blob_destroy (blob);
B
Behdad Esfahbod 已提交
422
      return nullptr;
423
    }
424 425 426
  }

  /* The checkSumAdjustment field in the 'head' table is now wrong,
B
Behdad Esfahbod 已提交
427 428
   * but that doesn't actually seem to cause any problems so we don't
   * bother. */
429

430
  hb_blob_destroy (blob);
B
Behdad Esfahbod 已提交
431
  return hb_blob_create ((const char *) new_sfnt_data, new_length,
B
Behdad Esfahbod 已提交
432
			 HB_MEMORY_MODE_WRITABLE, nullptr, free);
433 434
}

435 436
hb_uniscribe_shaper_face_data_t *
_hb_uniscribe_shaper_face_data_create (hb_face_t *face)
B
Behdad Esfahbod 已提交
437
{
438
  hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
B
Behdad Esfahbod 已提交
439
  if (unlikely (!data))
B
Behdad Esfahbod 已提交
440
    return nullptr;
B
Behdad Esfahbod 已提交
441

442 443 444 445
  data->funcs = hb_uniscribe_shaper_get_funcs ();
  if (unlikely (!data->funcs))
  {
    free (data);
B
Behdad Esfahbod 已提交
446
    return nullptr;
447 448
  }

B
Behdad Esfahbod 已提交
449
  hb_blob_t *blob = hb_face_reference_blob (face);
450
  if (unlikely (!hb_blob_get_length (blob)))
B
Behdad Esfahbod 已提交
451 452
    DEBUG_MSG (UNISCRIBE, face, "Face has empty blob");

453
  blob = _hb_rename_font (blob, data->face_name);
B
Behdad Esfahbod 已提交
454 455 456
  if (unlikely (!blob))
  {
    free (data);
B
Behdad Esfahbod 已提交
457
    return nullptr;
B
Behdad Esfahbod 已提交
458
  }
459 460

  DWORD num_fonts_installed;
B
Behdad Esfahbod 已提交
461
  data->fh = AddFontMemResourceEx ((void *) hb_blob_get_data (blob, nullptr),
462 463
				   hb_blob_get_length (blob),
				   0, &num_fonts_installed);
B
Behdad Esfahbod 已提交
464 465
  if (unlikely (!data->fh))
  {
B
Behdad Esfahbod 已提交
466
    DEBUG_MSG (UNISCRIBE, face, "Face AddFontMemResourceEx() failed");
467
    free (data);
B
Behdad Esfahbod 已提交
468
    return nullptr;
B
Behdad Esfahbod 已提交
469 470 471 472 473
  }

  return data;
}

474 475 476
void
_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
{
B
Behdad Esfahbod 已提交
477
  RemoveFontMemResourceEx (data->fh);
478 479
  free (data);
}
B
Behdad Esfahbod 已提交
480

481 482 483 484 485 486

/*
 * shaper font data
 */

struct hb_uniscribe_shaper_font_data_t {
B
Behdad Esfahbod 已提交
487
  HDC hdc;
B
Behdad Esfahbod 已提交
488
  LOGFONTW log_font;
B
Behdad Esfahbod 已提交
489 490
  HFONT hfont;
  SCRIPT_CACHE script_cache;
491
  double x_mult, y_mult; /* From LOGFONT space to HB space. */
492
};
B
Behdad Esfahbod 已提交
493

494 495
static bool
populate_log_font (LOGFONTW  *lf,
496 497
		   hb_font_t *font,
		   unsigned int font_size)
498 499
{
  memset (lf, 0, sizeof (*lf));
500
  lf->lfHeight = - (int) font_size;
501 502
  lf->lfCharSet = DEFAULT_CHARSET;

503 504
  hb_face_t *face = font->face;
  hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
505

506
  memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
507 508 509 510

  return true;
}

511 512 513
hb_uniscribe_shaper_font_data_t *
_hb_uniscribe_shaper_font_data_create (hb_font_t *font)
{
B
Behdad Esfahbod 已提交
514
  if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return nullptr;
B
Behdad Esfahbod 已提交
515

516
  hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
517
  if (unlikely (!data))
B
Behdad Esfahbod 已提交
518
    return nullptr;
519

520 521 522 523 524 525 526 527 528 529
  int font_size = font->face->get_upem (); /* Default... */
  /* No idea if the following is even a good idea. */
  if (font->y_ppem)
    font_size = font->y_ppem;

  if (font_size < 0)
    font_size = -font_size;
  data->x_mult = (double) font->x_scale / font_size;
  data->y_mult = (double) font->y_scale / font_size;

B
Behdad Esfahbod 已提交
530
  data->hdc = GetDC (nullptr);
531

532
  if (unlikely (!populate_log_font (&data->log_font, font, font_size))) {
533 534
    DEBUG_MSG (UNISCRIBE, font, "Font populate_log_font() failed");
    _hb_uniscribe_shaper_font_data_destroy (data);
B
Behdad Esfahbod 已提交
535
    return nullptr;
536 537 538 539 540 541
  }

  data->hfont = CreateFontIndirectW (&data->log_font);
  if (unlikely (!data->hfont)) {
    DEBUG_MSG (UNISCRIBE, font, "Font CreateFontIndirectW() failed");
    _hb_uniscribe_shaper_font_data_destroy (data);
B
Behdad Esfahbod 已提交
542
     return nullptr;
543 544 545 546 547
  }

  if (!SelectObject (data->hdc, data->hfont)) {
    DEBUG_MSG (UNISCRIBE, font, "Font SelectObject() failed");
    _hb_uniscribe_shaper_font_data_destroy (data);
B
Behdad Esfahbod 已提交
548
     return nullptr;
549 550 551 552 553 554 555
  }

  return data;
}

void
_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
B
Behdad Esfahbod 已提交
556 557
{
  if (data->hdc)
B
Behdad Esfahbod 已提交
558
    ReleaseDC (nullptr, data->hdc);
B
Behdad Esfahbod 已提交
559 560 561 562 563 564 565
  if (data->hfont)
    DeleteObject (data->hfont);
  if (data->script_cache)
    ScriptFreeCache (&data->script_cache);
  free (data);
}

B
Minor  
Behdad Esfahbod 已提交
566 567 568
LOGFONTW *
hb_uniscribe_font_get_logfontw (hb_font_t *font)
{
B
Behdad Esfahbod 已提交
569
  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr;
B
Minor  
Behdad Esfahbod 已提交
570 571 572 573 574 575 576
  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
  return &font_data->log_font;
}

HFONT
hb_uniscribe_font_get_hfont (hb_font_t *font)
{
B
Behdad Esfahbod 已提交
577
  if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr;
B
Minor  
Behdad Esfahbod 已提交
578 579 580 581
  hb_uniscribe_shaper_font_data_t *font_data =  HB_SHAPER_DATA_GET (font);
  return font_data->hfont;
}

582 583 584 585 586 587 588 589

/*
 * shaper shape_plan data
 */

struct hb_uniscribe_shaper_shape_plan_data_t {};

hb_uniscribe_shaper_shape_plan_data_t *
B
Minor  
Behdad Esfahbod 已提交
590 591
_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t    *shape_plan HB_UNUSED,
					     const hb_feature_t *user_features HB_UNUSED,
B
Behdad Esfahbod 已提交
592 593 594
					     unsigned int        num_user_features HB_UNUSED,
					     const int          *coords HB_UNUSED,
					     unsigned int        num_coords HB_UNUSED)
B
Behdad Esfahbod 已提交
595
{
596 597
  return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
}
B
Behdad Esfahbod 已提交
598

599
void
B
Minor  
Behdad Esfahbod 已提交
600
_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
601 602
{
}
B
Behdad Esfahbod 已提交
603 604


605 606 607
/*
 * shaper
 */
B
Behdad Esfahbod 已提交
608 609


610
hb_bool_t
B
Minor  
Behdad Esfahbod 已提交
611 612
_hb_uniscribe_shape (hb_shape_plan_t    *shape_plan,
		     hb_font_t          *font,
613 614 615
		     hb_buffer_t        *buffer,
		     const hb_feature_t *features,
		     unsigned int        num_features)
616
{
617 618 619
  hb_face_t *face = font->face;
  hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
  hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
620
  hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
621

622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
  /*
   * Set up features.
   */
  hb_auto_array_t<OPENTYPE_FEATURE_RECORD> feature_records;
  hb_auto_array_t<range_record_t> range_records;
  if (num_features)
  {
    /* Sort features by start/end events. */
    hb_auto_array_t<feature_event_t> feature_events;
    for (unsigned int i = 0; i < num_features; i++)
    {
      active_feature_t feature;
      feature.rec.tagFeature = hb_uint32_swap (features[i].tag);
      feature.rec.lParameter = features[i].value;
      feature.order = i;

      feature_event_t *event;

      event = feature_events.push ();
      if (unlikely (!event))
	goto fail_features;
      event->index = features[i].start;
      event->start = true;
      event->feature = feature;

      event = feature_events.push ();
      if (unlikely (!event))
	goto fail_features;
      event->index = features[i].end;
      event->start = false;
      event->feature = feature;
    }
B
Behdad Esfahbod 已提交
654
    feature_events.qsort ();
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
    /* Add a strategic final event. */
    {
      active_feature_t feature;
      feature.rec.tagFeature = 0;
      feature.rec.lParameter = 0;
      feature.order = num_features + 1;

      feature_event_t *event = feature_events.push ();
      if (unlikely (!event))
	goto fail_features;
      event->index = 0; /* This value does magic. */
      event->start = false;
      event->feature = feature;
    }

    /* Scan events and save features for each range. */
    hb_auto_array_t<active_feature_t> active_features;
    unsigned int last_index = 0;
    for (unsigned int i = 0; i < feature_events.len; i++)
    {
      feature_event_t *event = &feature_events[i];

      if (event->index != last_index)
      {
        /* Save a snapshot of active features and the range. */
	range_record_t *range = range_records.push ();
	if (unlikely (!range))
	  goto fail_features;

	unsigned int offset = feature_records.len;

B
Behdad Esfahbod 已提交
686
	active_features.qsort ();
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
	for (unsigned int j = 0; j < active_features.len; j++)
	{
	  if (!j || active_features[j].rec.tagFeature != feature_records[feature_records.len - 1].tagFeature)
	  {
	    OPENTYPE_FEATURE_RECORD *feature = feature_records.push ();
	    if (unlikely (!feature))
	      goto fail_features;
	    *feature = active_features[j].rec;
	  }
	  else
	  {
	    /* Overrides value for existing feature. */
	    feature_records[feature_records.len - 1].lParameter = active_features[j].rec.lParameter;
	  }
	}

	/* Will convert to pointer after all is ready, since feature_records.array
	 * may move as we grow it. */
	range->props.potfRecords = reinterpret_cast<OPENTYPE_FEATURE_RECORD *> (offset);
	range->props.cotfRecords = feature_records.len - offset;
	range->index_first = last_index;
	range->index_last  = event->index - 1;

	last_index = event->index;
      }

      if (event->start) {
        active_feature_t *feature = active_features.push ();
	if (unlikely (!feature))
	  goto fail_features;
	*feature = event->feature;
      } else {
        active_feature_t *feature = active_features.find (&event->feature);
	if (feature)
	  active_features.remove (feature - active_features.array);
      }
    }

    if (!range_records.len) /* No active feature found. */
      goto fail_features;

    /* Fixup the pointers. */
    for (unsigned int i = 0; i < range_records.len; i++)
    {
      range_record_t *range = &range_records[i];
J
Jonathan Kew 已提交
732
      range->props.potfRecords = feature_records.array + reinterpret_cast<uintptr_t> (range->props.potfRecords);
733 734 735 736 737 738 739 740
    }
  }
  else
  {
  fail_features:
    num_features = 0;
  }

B
Behdad Esfahbod 已提交
741 742
#define FAIL(...) \
  HB_STMT_START { \
B
Behdad Esfahbod 已提交
743
    DEBUG_MSG (UNISCRIBE, nullptr, __VA_ARGS__); \
744
    return false; \
B
Behdad Esfahbod 已提交
745 746 747 748
  } HB_STMT_END;

  HRESULT hr;

749 750 751
retry:

  unsigned int scratch_size;
B
Behdad Esfahbod 已提交
752
  hb_buffer_t::scratch_buffer_t *scratch = buffer->get_scratch_buffer (&scratch_size);
753

B
Behdad Esfahbod 已提交
754 755 756 757 758 759 760 761
#define ALLOCATE_ARRAY(Type, name, len) \
  Type *name = (Type *) scratch; \
  { \
    unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
    assert (_consumed <= scratch_size); \
    scratch += _consumed; \
    scratch_size -= _consumed; \
  }
762 763 764

#define utf16_index() var1.u32

B
Behdad Esfahbod 已提交
765 766
  ALLOCATE_ARRAY (WCHAR, pchars, buffer->len * 2);

767
  unsigned int chars_len = 0;
768 769
  for (unsigned int i = 0; i < buffer->len; i++)
  {
770 771
    hb_codepoint_t c = buffer->info[i].codepoint;
    buffer->info[i].utf16_index() = chars_len;
772
    if (likely (c <= 0xFFFFu))
773
      pchars[chars_len++] = c;
774 775
    else if (unlikely (c > 0x10FFFFu))
      pchars[chars_len++] = 0xFFFDu;
776
    else {
777
      pchars[chars_len++] = 0xD800u + ((c - 0x10000u) >> 10);
B
Behdad Esfahbod 已提交
778
      pchars[chars_len++] = 0xDC00u + ((c - 0x10000u) & ((1u << 10) - 1));
779 780 781 782 783 784
    }
  }

  ALLOCATE_ARRAY (WORD, log_clusters, chars_len);
  ALLOCATE_ARRAY (SCRIPT_CHARPROP, char_props, chars_len);

785 786 787 788 789 790 791 792 793
  if (num_features)
  {
    /* Need log_clusters to assign features. */
    chars_len = 0;
    for (unsigned int i = 0; i < buffer->len; i++)
    {
      hb_codepoint_t c = buffer->info[i].codepoint;
      unsigned int cluster = buffer->info[i].cluster;
      log_clusters[chars_len++] = cluster;
794
      if (hb_in_range (c, 0x10000u, 0x10FFFFu))
795 796 797 798
	log_clusters[chars_len++] = cluster; /* Surrogates. */
    }
  }

799 800 801 802 803 804 805 806
  /* The -2 in the following is to compensate for possible
   * alignment needed after the WORD array.  sizeof(WORD) == 2. */
  unsigned int glyphs_size = (scratch_size * sizeof (int) - 2)
			   / (sizeof (WORD) +
			      sizeof (SCRIPT_GLYPHPROP) +
			      sizeof (int) +
			      sizeof (GOFFSET) +
			      sizeof (uint32_t));
807 808 809 810 811 812 813

  ALLOCATE_ARRAY (WORD, glyphs, glyphs_size);
  ALLOCATE_ARRAY (SCRIPT_GLYPHPROP, glyph_props, glyphs_size);
  ALLOCATE_ARRAY (int, advances, glyphs_size);
  ALLOCATE_ARRAY (GOFFSET, offsets, glyphs_size);
  ALLOCATE_ARRAY (uint32_t, vis_clusters, glyphs_size);

814 815 816 817 818 819 820 821
  /* Note:
   * We can't touch the contents of glyph_props.  Our fallback
   * implementations of Shape and Place functions use that buffer
   * by casting it to a different type.  It works because they
   * both agree about it, but if we want to access it here we
   * need address that issue first.
   */

B
Behdad Esfahbod 已提交
822
#undef ALLOCATE_ARRAY
823

B
Behdad Esfahbod 已提交
824
#define MAX_ITEMS 256
825 826

  SCRIPT_ITEM items[MAX_ITEMS + 1];
827
  SCRIPT_CONTROL bidi_control = {0};
828
  SCRIPT_STATE bidi_state = {0};
829
  ULONG script_tags[MAX_ITEMS];
830 831
  int item_count;

832
  /* MinGW32 doesn't define fMergeNeutralItems, so we bruteforce */
833
  //bidi_control.fMergeNeutralItems = true;
B
Behdad Esfahbod 已提交
834
  *(uint32_t*)&bidi_control |= 1u<<24;
835

836
  bidi_state.uBidiLevel = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
837
  bidi_state.fOverrideDirection = 1;
838

B
Behdad Esfahbod 已提交
839
  hr = funcs->ScriptItemizeOpenType (pchars,
840 841 842 843 844 845 846
				     chars_len,
				     MAX_ITEMS,
				     &bidi_control,
				     &bidi_state,
				     items,
				     script_tags,
				     &item_count);
847
  if (unlikely (FAILED (hr)))
B
Behdad Esfahbod 已提交
848
    FAIL ("ScriptItemizeOpenType() failed: 0x%08xL", hr);
849 850 851

#undef MAX_ITEMS

852
  OPENTYPE_TAG language_tag = hb_uint32_swap (hb_ot_tag_from_language (buffer->props.language));
853 854
  hb_auto_array_t<TEXTRANGE_PROPERTIES*> range_properties;
  hb_auto_array_t<int> range_char_counts;
855 856 857

  unsigned int glyphs_offset = 0;
  unsigned int glyphs_len;
858
  bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
859
  for (int i = 0; i < item_count; i++)
860
  {
B
Behdad Esfahbod 已提交
861 862 863
    unsigned int chars_offset = items[i].iCharPos;
    unsigned int item_chars_len = items[i + 1].iCharPos - chars_offset;

864 865 866
    if (num_features)
    {
      range_properties.shrink (0);
867
      range_char_counts.shrink (0);
868

869
      range_record_t *last_range = &range_records[0];
870

871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
      for (unsigned int k = chars_offset; k < chars_offset + item_chars_len; k++)
      {
	range_record_t *range = last_range;
	while (log_clusters[k] < range->index_first)
	  range--;
	while (log_clusters[k] > range->index_last)
	  range++;
	if (!range_properties.len ||
	    &range->props != range_properties[range_properties.len - 1])
	{
	  TEXTRANGE_PROPERTIES **props = range_properties.push ();
	  int *c = range_char_counts.push ();
	  if (unlikely (!props || !c))
	  {
	    range_properties.shrink (0);
	    range_char_counts.shrink (0);
	    break;
	  }
	  *props = &range->props;
	  *c = 1;
	}
	else
	{
	  range_char_counts[range_char_counts.len - 1]++;
	}

	last_range = range;
      }
899 900
    }

901 902 903 904
    /* Asking for glyphs in logical order circumvents at least
     * one bug in Uniscribe. */
    items[i].a.fLogicalOrder = true;

905
  retry_shape:
906 907 908 909 910
    hr = funcs->ScriptShapeOpenType (font_data->hdc,
				     &font_data->script_cache,
				     &items[i].a,
				     script_tags[i],
				     language_tag,
911 912 913
				     range_char_counts.array,
				     range_properties.array,
				     range_properties.len,
B
Behdad Esfahbod 已提交
914
				     pchars + chars_offset,
915 916 917 918 919 920 921 922
				     item_chars_len,
				     glyphs_size - glyphs_offset,
				     /* out */
				     log_clusters + chars_offset,
				     char_props + chars_offset,
				     glyphs + glyphs_offset,
				     glyph_props + glyphs_offset,
				     (int *) &glyphs_len);
B
Behdad Esfahbod 已提交
923 924 925

    if (unlikely (items[i].a.fNoGlyphIndex))
      FAIL ("ScriptShapeOpenType() set fNoGlyphIndex");
926
    if (unlikely (hr == E_OUTOFMEMORY || hr == E_NOT_SUFFICIENT_BUFFER))
B
Behdad Esfahbod 已提交
927
    {
B
Minor  
Behdad Esfahbod 已提交
928
      if (unlikely (!buffer->ensure (buffer->allocated * 2)))
B
Behdad Esfahbod 已提交
929 930 931 932
	FAIL ("Buffer resize failed");
      goto retry;
    }
    if (unlikely (hr == USP_E_SCRIPT_NOT_IN_FONT))
933 934 935 936 937 938
    {
      if (items[i].a.eScript == SCRIPT_UNDEFINED)
	FAIL ("ScriptShapeOpenType() failed: Font doesn't support script");
      items[i].a.eScript = SCRIPT_UNDEFINED;
      goto retry_shape;
    }
B
Behdad Esfahbod 已提交
939
    if (unlikely (FAILED (hr)))
940
    {
B
Behdad Esfahbod 已提交
941
      FAIL ("ScriptShapeOpenType() failed: 0x%08xL", hr);
942 943 944 945
    }

    for (unsigned int j = chars_offset; j < chars_offset + item_chars_len; j++)
      log_clusters[j] += glyphs_offset;
B
Behdad Esfahbod 已提交
946

947 948 949 950 951
    hr = funcs->ScriptPlaceOpenType (font_data->hdc,
				     &font_data->script_cache,
				     &items[i].a,
				     script_tags[i],
				     language_tag,
952 953 954
				     range_char_counts.array,
				     range_properties.array,
				     range_properties.len,
B
Behdad Esfahbod 已提交
955
				     pchars + chars_offset,
956 957 958 959 960 961 962 963 964
				     log_clusters + chars_offset,
				     char_props + chars_offset,
				     item_chars_len,
				     glyphs + glyphs_offset,
				     glyph_props + glyphs_offset,
				     glyphs_len,
				     /* out */
				     advances + glyphs_offset,
				     offsets + glyphs_offset,
B
Behdad Esfahbod 已提交
965
				     nullptr);
B
Behdad Esfahbod 已提交
966 967 968
    if (unlikely (FAILED (hr)))
      FAIL ("ScriptPlaceOpenType() failed: 0x%08xL", hr);

B
Behdad Esfahbod 已提交
969 970 971 972 973 974 975 976
    if (DEBUG_ENABLED (UNISCRIBE))
      fprintf (stderr, "Item %d RTL %d LayoutRTL %d LogicalOrder %d ScriptTag %c%c%c%c\n",
	       i,
	       items[i].a.fRTL,
	       items[i].a.fLayoutRTL,
	       items[i].a.fLogicalOrder,
	       HB_UNTAG (hb_uint32_swap (script_tags[i])));

B
Behdad Esfahbod 已提交
977
    glyphs_offset += glyphs_len;
978 979 980 981 982 983 984
  }
  glyphs_len = glyphs_offset;

  /* Ok, we've got everything we need, now compose output buffer,
   * very, *very*, carefully! */

  /* Calculate visual-clusters.  That's what we ship. */
985 986
  for (unsigned int i = 0; i < glyphs_len; i++)
    vis_clusters[i] = -1;
987 988 989 990
  for (unsigned int i = 0; i < buffer->len; i++) {
    uint32_t *p = &vis_clusters[log_clusters[buffer->info[i].utf16_index()]];
    *p = MIN (*p, buffer->info[i].cluster);
  }
991 992 993
  for (unsigned int i = 1; i < glyphs_len; i++)
    if (vis_clusters[i] == -1)
      vis_clusters[i] = vis_clusters[i - 1];
994 995 996

#undef utf16_index

B
Minor  
Behdad Esfahbod 已提交
997
  if (unlikely (!buffer->ensure (glyphs_len)))
998
    FAIL ("Buffer in error");
999

1000
#undef FAIL
1001 1002

  /* Set glyph infos */
1003
  buffer->len = 0;
1004 1005
  for (unsigned int i = 0; i < glyphs_len; i++)
  {
1006
    hb_glyph_info_t *info = &buffer->info[buffer->len++];
1007 1008 1009 1010 1011 1012

    info->codepoint = glyphs[i];
    info->cluster = vis_clusters[i];

    /* The rest is crap.  Let's store position info there for now. */
    info->mask = advances[i];
1013 1014
    info->var1.i32 = offsets[i].du;
    info->var2.i32 = offsets[i].dv;
1015 1016 1017 1018
  }

  /* Set glyph positions */
  buffer->clear_positions ();
1019
  double x_mult = font_data->x_mult, y_mult = font_data->y_mult;
1020 1021 1022 1023 1024 1025
  for (unsigned int i = 0; i < glyphs_len; i++)
  {
    hb_glyph_info_t *info = &buffer->info[i];
    hb_glyph_position_t *pos = &buffer->pos[i];

    /* TODO vertical */
1026
    pos->x_advance = x_mult * (int32_t) info->mask;
1027 1028
    pos->x_offset = x_mult * (backward ? -info->var1.i32 : info->var1.i32);
    pos->y_offset = y_mult * info->var2.i32;
1029 1030
  }

1031 1032 1033
  if (backward)
    hb_buffer_reverse (buffer);

1034 1035
  buffer->unsafe_to_break_all ();

1036
  /* Wow, done! */
1037
  return true;
1038 1039 1040
}