hb-ft.cc 15.6 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2 3
 * Copyright © 2009  Red Hat, Inc.
 * Copyright © 2009  Keith Stribley
4
 * Copyright © 2015  Google, Inc.
B
Behdad Esfahbod 已提交
5
 *
B
Behdad Esfahbod 已提交
6
 *  This is part of HarfBuzz, a text shaping library.
B
Behdad Esfahbod 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * 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.
 *
 * Red Hat Author(s): Behdad Esfahbod
27
 * Google Author(s): Behdad Esfahbod
B
Behdad Esfahbod 已提交
28 29
 */

30
#include "hb-private.hh"
B
Behdad Esfahbod 已提交
31 32 33

#include "hb-ft.h"

34
#include "hb-font-private.hh"
B
Behdad Esfahbod 已提交
35

36
#include FT_ADVANCES_H
B
Behdad Esfahbod 已提交
37 38
#include FT_TRUETYPE_TABLES_H

B
Behdad Esfahbod 已提交
39 40


41 42 43 44 45
#ifndef HB_DEBUG_FT
#define HB_DEBUG_FT (HB_DEBUG+0)
#endif


46 47 48 49 50
/* TODO:
 *
 * In general, this file does a fine job of what it's supposed to do.
 * There are, however, things that need more work:
 *
51 52
 *   - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
 *     Have not investigated.
53
 *
54
 *   - FreeType works in 26.6 mode.  Clients can decide to use that mode, and everything
B
Behdad Esfahbod 已提交
55 56 57
 *     would work fine.  However, we also abuse this API for performing in font-space,
 *     but don't pass the correct flags to FreeType.  We just abuse the no-hinting mode
 *     for that, such that no rounding etc happens.  As such, we don't set ppem, and
58 59
 *     pass NO_HINTING as load_flags.  Would be much better to use NO_SCALE, and scale
 *     ourselves, like we do in uniscribe, etc.
B
Behdad Esfahbod 已提交
60
 *
61 62
 *   - We don't handle / allow for emboldening / obliqueing.
 *
63
 *   - In the future, we should add constructors to create fonts in font space?
64
 *
B
Minor  
Behdad Esfahbod 已提交
65
 *   - FT_Load_Glyph() is exteremely costly.  Do something about it?
66 67 68
 */


69 70 71 72 73 74 75 76 77 78 79 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
struct hb_ft_font_t
{
  FT_Face ft_face;
  int load_flags;
  bool unref; /* Whether to destroy ft_face when done. */
};

static hb_ft_font_t *
_hb_ft_font_create (FT_Face ft_face, bool unref)
{
  hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));

  if (unlikely (!ft_font))
    return NULL;

  ft_font->ft_face = ft_face;
  ft_font->unref = unref;

  ft_font->load_flags = FT_LOAD_DEFAULT;

  return ft_font;
}

static void
_hb_ft_font_destroy (hb_ft_font_t *ft_font)
{
  if (ft_font->unref)
    FT_Done_Face (ft_font->ft_face);

  free (ft_font);
}

void
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
{
  if (font->immutable)
    return;

  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
    return;

  hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;

  ft_font->load_flags = load_flags;
}

int
hb_ft_font_get_load_flags (hb_font_t *font)
{
  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
    return 0;

  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;

  return ft_font->load_flags;
}

FT_Face
hb_ft_font_get_face (hb_font_t *font)
{
  if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
    return NULL;

  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;

  return ft_font->ft_face;
}



139
static hb_bool_t
140 141 142 143 144 145 146
hb_ft_get_glyph (hb_font_t *font HB_UNUSED,
		 void *font_data,
		 hb_codepoint_t unicode,
		 hb_codepoint_t variation_selector,
		 hb_codepoint_t *glyph,
		 void *user_data HB_UNUSED)

B
Behdad Esfahbod 已提交
147
{
148
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
149
  unsigned int g;
150

151
  if (likely (!variation_selector))
152
    g = FT_Get_Char_Index (ft_font->ft_face, unicode);
153
  else
154
    g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
155

156 157 158 159 160
  if (unlikely (!g))
    return false;

  *glyph = g;
  return true;
161 162
}

163
static hb_position_t
164 165 166 167 168
hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED,
			   void *font_data,
			   hb_codepoint_t glyph,
			   void *user_data HB_UNUSED)
{
169
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
170
  FT_Fixed v;
171

172
  if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
173
    return 0;
174

175 176 177
  if (font->x_scale < 0)
    v = -v;

178
  return (v + (1<<9)) >> 10;
179
}
180

181
static hb_position_t
182 183 184 185 186
hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED,
			   void *font_data,
			   hb_codepoint_t glyph,
			   void *user_data HB_UNUSED)
{
187
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
188
  FT_Fixed v;
189

190
  if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
191
    return 0;
192

193 194 195
  if (font->y_scale < 0)
    v = -v;

B
Behdad Esfahbod 已提交
196 197
  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
   * have a Y growing upward.  Hence the extra negation. */
198
  return (-v + (1<<9)) >> 10;
B
Behdad Esfahbod 已提交
199 200
}

B
Behdad Esfahbod 已提交
201 202 203 204
static hb_bool_t
hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED,
			  void *font_data HB_UNUSED,
			  hb_codepoint_t glyph HB_UNUSED,
B
Behdad Esfahbod 已提交
205 206
			  hb_position_t *x HB_UNUSED,
			  hb_position_t *y HB_UNUSED,
B
Behdad Esfahbod 已提交
207 208 209
			  void *user_data HB_UNUSED)
{
  /* We always work in the horizontal coordinates. */
210
  return true;
B
Behdad Esfahbod 已提交
211 212
}

213 214 215 216
static hb_bool_t
hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED,
			  void *font_data,
			  hb_codepoint_t glyph,
B
Behdad Esfahbod 已提交
217 218
			  hb_position_t *x,
			  hb_position_t *y,
219
			  void *user_data HB_UNUSED)
220
{
221 222
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
  FT_Face ft_face = ft_font->ft_face;
223

224
  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
225
    return false;
226

B
Behdad Esfahbod 已提交
227 228 229 230 231
  /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
   * have a Y growing upward.  Hence the extra negation. */
  *x = ft_face->glyph->metrics.horiBearingX -   ft_face->glyph->metrics.vertBearingX;
  *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);

232 233 234 235 236
  if (font->x_scale < 0)
    *x = -*x;
  if (font->y_scale < 0)
    *y = -*y;

237
  return true;
238 239
}

240
static hb_position_t
241
hb_ft_get_glyph_h_kerning (hb_font_t *font,
B
Behdad Esfahbod 已提交
242 243 244 245
			   void *font_data,
			   hb_codepoint_t left_glyph,
			   hb_codepoint_t right_glyph,
			   void *user_data HB_UNUSED)
246
{
247
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
248
  FT_Vector kerningv;
249

250
  FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
251
  if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
252
    return 0;
253

254
  return kerningv.x;
255 256
}

257
static hb_position_t
B
Behdad Esfahbod 已提交
258 259 260 261 262
hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED,
			   void *font_data HB_UNUSED,
			   hb_codepoint_t top_glyph HB_UNUSED,
			   hb_codepoint_t bottom_glyph HB_UNUSED,
			   void *user_data HB_UNUSED)
263 264
{
  /* FreeType API doesn't support vertical kerning */
265
  return 0;
266 267 268
}

static hb_bool_t
269
hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED,
270
			 void *font_data,
271
			 hb_codepoint_t glyph,
272
			 hb_glyph_extents_t *extents,
273
			 void *user_data HB_UNUSED)
274
{
275 276
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
  FT_Face ft_face = ft_font->ft_face;
277

278
  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
279
    return false;
280 281 282 283

  extents->x_bearing = ft_face->glyph->metrics.horiBearingX;
  extents->y_bearing = ft_face->glyph->metrics.horiBearingY;
  extents->width = ft_face->glyph->metrics.width;
284
  extents->height = -ft_face->glyph->metrics.height;
285
  return true;
286 287
}

288
static hb_bool_t
B
Behdad Esfahbod 已提交
289 290 291 292 293 294 295
hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED,
			       void *font_data,
			       hb_codepoint_t glyph,
			       unsigned int point_index,
			       hb_position_t *x,
			       hb_position_t *y,
			       void *user_data HB_UNUSED)
296
{
297 298
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
  FT_Face ft_face = ft_font->ft_face;
B
Behdad Esfahbod 已提交
299

300
  if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
301
      return false;
B
Behdad Esfahbod 已提交
302

303
  if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE))
304
      return false;
B
Behdad Esfahbod 已提交
305

306
  if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points))
307
      return false;
308

309 310
  *x = ft_face->glyph->outline.points[point_index].x;
  *y = ft_face->glyph->outline.points[point_index].y;
311

312
  return true;
B
Behdad Esfahbod 已提交
313 314
}

315
static hb_bool_t
B
Minor  
Behdad Esfahbod 已提交
316
hb_ft_get_glyph_name (hb_font_t *font HB_UNUSED,
317 318 319 320 321
		      void *font_data,
		      hb_codepoint_t glyph,
		      char *name, unsigned int size,
		      void *user_data HB_UNUSED)
{
322
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
323

324
  hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
325 326
  if (ret && (size && !*name))
    ret = false;
327 328 329 330 331

  return ret;
}

static hb_bool_t
B
Minor  
Behdad Esfahbod 已提交
332
hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
333 334 335 336 337
			   void *font_data,
			   const char *name, int len, /* -1 means nul-terminated */
			   hb_codepoint_t *glyph,
			   void *user_data HB_UNUSED)
{
338 339
  const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
  FT_Face ft_face = ft_font->ft_face;
340 341 342 343 344 345 346 347 348 349 350 351

  if (len < 0)
    *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
  else {
    /* Make a nul-terminated version. */
    char buf[128];
    len = MIN (len, (int) sizeof (buf) - 1);
    strncpy (buf, name, len);
    buf[len] = '\0';
    *glyph = FT_Get_Name_Index (ft_face, buf);
  }

352 353 354 355 356 357 358 359 360
  if (*glyph == 0)
  {
    /* Check whether the given name was actually the name of glyph 0. */
    char buf[128];
    if (!FT_Get_Glyph_Name(ft_face, 0, buf, sizeof (buf)) &&
        len < 0 ? !strcmp (buf, name) : !strncmp (buf, name, len))
      return true;
  }

361 362 363 364
  return *glyph != 0;
}


365 366
static void
_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
367 368 369
{
  static const hb_font_funcs_t ft_ffuncs = {
    HB_OBJECT_HEADER_STATIC,
370

371
    true, /* immutable */
372

373
    {
374
#define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name,
375
      HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
376
#undef HB_FONT_FUNC_IMPLEMENT
377 378
    }
  };
B
Behdad Esfahbod 已提交
379

380 381 382 383
  hb_font_set_funcs (font,
		     const_cast<hb_font_funcs_t *> (&ft_ffuncs),
		     _hb_ft_font_create (ft_face, unref),
		     (hb_destroy_func_t) _hb_ft_font_destroy);
B
Behdad Esfahbod 已提交
384 385 386 387
}


static hb_blob_t *
388
reference_table  (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
B
Behdad Esfahbod 已提交
389 390 391 392 393 394
{
  FT_Face ft_face = (FT_Face) user_data;
  FT_Byte *buffer;
  FT_ULong  length = 0;
  FT_Error error;

B
Behdad Esfahbod 已提交
395
  /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */
396

B
Behdad Esfahbod 已提交
397 398
  error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length);
  if (error)
399
    return NULL;
B
Behdad Esfahbod 已提交
400

401
  buffer = (FT_Byte *) malloc (length);
B
Behdad Esfahbod 已提交
402
  if (buffer == NULL)
403
    return NULL;
B
Behdad Esfahbod 已提交
404 405 406

  error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
  if (error)
407
    return NULL;
B
Behdad Esfahbod 已提交
408 409 410

  return hb_blob_create ((const char *) buffer, length,
			 HB_MEMORY_MODE_WRITABLE,
411
			 buffer, free);
B
Behdad Esfahbod 已提交
412 413
}

414 415 416 417 418 419 420 421
/**
 * hb_ft_face_create:
 * @ft_face: (destroy destroy) (scope notified): 
 * @destroy:
 *
 * 
 *
 * Return value: (transfer full): 
B
Behdad Esfahbod 已提交
422
 * Since: 0.9.2
423
 **/
B
Behdad Esfahbod 已提交
424 425 426 427 428 429
hb_face_t *
hb_ft_face_create (FT_Face           ft_face,
		   hb_destroy_func_t destroy)
{
  hb_face_t *face;

430
  if (ft_face->stream->read == NULL) {
B
Behdad Esfahbod 已提交
431 432 433 434
    hb_blob_t *blob;

    blob = hb_blob_create ((const char *) ft_face->stream->base,
			   (unsigned int) ft_face->stream->size,
B
Behdad Esfahbod 已提交
435
			   HB_MEMORY_MODE_READONLY,
436
			   ft_face, destroy);
437
    face = hb_face_create (blob, ft_face->face_index);
B
Behdad Esfahbod 已提交
438 439
    hb_blob_destroy (blob);
  } else {
440
    face = hb_face_create_for_tables (reference_table, ft_face, destroy);
B
Behdad Esfahbod 已提交
441 442
  }

B
Behdad Esfahbod 已提交
443 444 445
  hb_face_set_index (face, ft_face->face_index);
  hb_face_set_upem (face, ft_face->units_per_EM);

B
Behdad Esfahbod 已提交
446 447 448
  return face;
}

449 450 451 452 453 454 455
/**
 * hb_ft_face_create_referenced:
 * @ft_face:
 *
 * 
 *
 * Return value: (transfer full): 
S
Sascha Brawer 已提交
456
 * Since: 0.9.38
457 458 459 460 461 462 463 464
 **/
hb_face_t *
hb_ft_face_create_referenced (FT_Face ft_face)
{
  FT_Reference_Face (ft_face);
  return hb_ft_face_create (ft_face, (hb_destroy_func_t) FT_Done_Face);
}

B
Behdad Esfahbod 已提交
465 466 467
static void
hb_ft_face_finalize (FT_Face ft_face)
{
468
  hb_face_destroy ((hb_face_t *) ft_face->generic.data);
B
Behdad Esfahbod 已提交
469 470
}

471 472 473 474 475 476 477
/**
 * hb_ft_face_create_cached:
 * @ft_face: 
 *
 * 
 *
 * Return value: (transfer full): 
B
Behdad Esfahbod 已提交
478
 * Since: 0.9.2
479
 **/
B
Behdad Esfahbod 已提交
480 481 482
hb_face_t *
hb_ft_face_create_cached (FT_Face ft_face)
{
483
  if (unlikely (!ft_face->generic.data || ft_face->generic.finalizer != (FT_Generic_Finalizer) hb_ft_face_finalize))
B
Behdad Esfahbod 已提交
484 485
  {
    if (ft_face->generic.finalizer)
B
Behdad Esfahbod 已提交
486
      ft_face->generic.finalizer (ft_face);
B
Behdad Esfahbod 已提交
487

B
Behdad Esfahbod 已提交
488
    ft_face->generic.data = hb_ft_face_create (ft_face, NULL);
B
Behdad Esfahbod 已提交
489
    ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize;
B
Behdad Esfahbod 已提交
490
  }
B
Behdad Esfahbod 已提交
491

492
  return hb_face_reference ((hb_face_t *) ft_face->generic.data);
B
Behdad Esfahbod 已提交
493 494
}

B
Behdad Esfahbod 已提交
495

496 497 498 499 500 501 502 503
/**
 * hb_ft_font_create:
 * @ft_face: (destroy destroy) (scope notified): 
 * @destroy:
 *
 * 
 *
 * Return value: (transfer full): 
B
Behdad Esfahbod 已提交
504
 * Since: 0.9.2
505
 **/
B
Behdad Esfahbod 已提交
506 507 508 509 510
hb_font_t *
hb_ft_font_create (FT_Face           ft_face,
		   hb_destroy_func_t destroy)
{
  hb_font_t *font;
B
Behdad Esfahbod 已提交
511
  hb_face_t *face;
B
Behdad Esfahbod 已提交
512

B
Behdad Esfahbod 已提交
513 514 515
  face = hb_ft_face_create (ft_face, destroy);
  font = hb_font_create (face);
  hb_face_destroy (face);
516
  _hb_ft_font_set_funcs (font, ft_face, false);
B
Behdad Esfahbod 已提交
517
  hb_font_set_scale (font,
B
Behdad Esfahbod 已提交
518 519
		     (int) (((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16),
		     (int) (((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM + (1<<15)) >> 16));
B
Behdad Esfahbod 已提交
520
#if 0 /* hb-ft works in no-hinting model */
B
Behdad Esfahbod 已提交
521 522 523
  hb_font_set_ppem (font,
		    ft_face->size->metrics.x_ppem,
		    ft_face->size->metrics.y_ppem);
B
Behdad Esfahbod 已提交
524
#endif
B
Behdad Esfahbod 已提交
525 526 527

  return font;
}
B
Behdad Esfahbod 已提交
528

529 530 531 532 533 534 535
/**
 * hb_ft_font_create_referenced:
 * @ft_face:
 *
 * 
 *
 * Return value: (transfer full): 
S
Sascha Brawer 已提交
536
 * Since: 0.9.38
537 538 539 540 541 542 543 544
 **/
hb_font_t *
hb_ft_font_create_referenced (FT_Face ft_face)
{
  FT_Reference_Face (ft_face);
  return hb_ft_font_create (ft_face, (hb_destroy_func_t) FT_Done_Face);
}

B
Behdad Esfahbod 已提交
545

B
Behdad Esfahbod 已提交
546 547
/* Thread-safe, lock-free, FT_Library */

548 549
static FT_Library ft_library;

550 551
#ifdef HB_USE_ATEXIT
static
552 553 554 555
void free_ft_library (void)
{
  FT_Done_FreeType (ft_library);
}
556
#endif
557

558
static FT_Library
559
get_ft_library (void)
560
{
561 562 563 564
retry:
  FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);

  if (unlikely (!library))
565
  {
566 567 568 569 570 571 572
    /* Not found; allocate one. */
    if (FT_Init_FreeType (&library))
      return NULL;

    if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) {
      FT_Done_FreeType (library);
      goto retry;
573
    }
574

575
#ifdef HB_USE_ATEXIT
576 577 578 579 580
    atexit (free_ft_library); /* First person registers atexit() callback. */
#endif
  }

  return library;
581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
}

static void
_release_blob (FT_Face ft_face)
{
  hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
}

void
hb_ft_font_set_funcs (hb_font_t *font)
{
  hb_blob_t *blob = hb_face_reference_blob (font->face);
  unsigned int blob_length;
  const char *blob_data = hb_blob_get_data (blob, &blob_length);
  if (unlikely (!blob_length))
    DEBUG_MSG (FT, font, "Font face has empty blob");

  FT_Face ft_face = NULL;
599
  FT_Error err = FT_New_Memory_Face (get_ft_library (),
600 601 602 603 604 605 606 607 608 609 610
				     (const FT_Byte *) blob_data,
				     blob_length,
				     hb_face_get_index (font->face),
				     &ft_face);

  if (unlikely (err)) {
    hb_blob_destroy (blob);
    DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed");
    return;
  }

611 612
  FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);

613
  FT_Set_Char_Size (ft_face,
614
		    abs (font->x_scale), abs (font->y_scale),
B
Behdad Esfahbod 已提交
615 616
		    0, 0);
#if 0
617 618
		    font->x_ppem * 72 * 64 / font->x_scale,
		    font->y_ppem * 72 * 64 / font->y_scale);
B
Behdad Esfahbod 已提交
619
#endif
620 621 622 623 624 625
  if (font->x_scale < 0 || font->y_scale < 0)
  {
    FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0,
			  0, font->y_scale < 0 ? -1 : +1};
    FT_Set_Transform (ft_face, &matrix, NULL);
  }
626 627 628 629

  ft_face->generic.data = blob;
  ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob;

630 631
  _hb_ft_font_set_funcs (font, ft_face, true);
  hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
B
Behdad Esfahbod 已提交
632
}