hb-ot-font.cc 19.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/*
 * Copyright © 2011,2014  Google, Inc.
 *
 *  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, Roozbeh Pournader
 */

#include "hb-private.hh"

#include "hb-ot.h"

#include "hb-font-private.hh"

33
#include "hb-ot-cmap-table.hh"
34
#include "hb-ot-cbdt-table.hh"
35 36
#include "hb-ot-glyf-table.hh"
#include "hb-ot-head-table.hh"
37 38
#include "hb-ot-hhea-table.hh"
#include "hb-ot-hmtx-table.hh"
39
#include "hb-ot-os2-table.hh"
B
Behdad Esfahbod 已提交
40
#include "hb-ot-var-hvar-table.hh"
41
//#include "hb-ot-post-table.hh"
42 43


B
Behdad Esfahbod 已提交
44
struct hb_ot_face_metrics_accelerator_t
B
Behdad Esfahbod 已提交
45 46 47
{
  unsigned int num_metrics;
  unsigned int num_advances;
48
  unsigned int default_advance;
49 50 51
  unsigned short ascender;
  unsigned short descender;
  unsigned short line_gap;
B
Behdad Esfahbod 已提交
52
  bool has_font_extents;
53

B
Minor  
Behdad Esfahbod 已提交
54
  const OT::hmtxvmtx *table;
B
Behdad Esfahbod 已提交
55 56
  hb_blob_t *blob;

57 58 59
  const OT::HVARVVAR *var;
  hb_blob_t *var_blob;

B
Behdad Esfahbod 已提交
60
  inline void init (hb_face_t *face,
61 62
		    hb_tag_t _hea_tag,
		    hb_tag_t _mtx_tag,
63
		    hb_tag_t _var_tag,
64 65
		    hb_tag_t os2_tag,
		    unsigned int default_advance = 0)
B
Behdad Esfahbod 已提交
66
  {
67
    this->default_advance = default_advance ? default_advance : face->get_upem ();
B
Behdad Esfahbod 已提交
68

69 70 71 72 73
    bool got_font_extents = false;
    if (os2_tag)
    {
      hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>::sanitize (face->reference_table (os2_tag));
      const OT::os2 *os2 = OT::Sanitizer<OT::os2>::lock_instance (os2_blob);
74 75 76 77 78 79 80 81
#define USE_TYPO_METRICS (1u<<7)
      if (0 != (os2->fsSelection & USE_TYPO_METRICS))
      {
	this->ascender = os2->sTypoAscender;
	this->descender = os2->sTypoDescender;
	this->line_gap = os2->sTypoLineGap;
	got_font_extents = (this->ascender | this->descender) != 0;
      }
82 83 84
      hb_blob_destroy (os2_blob);
    }

B
Behdad Esfahbod 已提交
85
    hb_blob_t *_hea_blob = OT::Sanitizer<OT::_hea>::sanitize (face->reference_table (_hea_tag));
B
Behdad Esfahbod 已提交
86 87
    const OT::_hea *_hea = OT::Sanitizer<OT::_hea>::lock_instance (_hea_blob);
    this->num_advances = _hea->numberOfLongMetrics;
88 89 90 91 92
    if (!got_font_extents)
    {
      this->ascender = _hea->ascender;
      this->descender = _hea->descender;
      this->line_gap = _hea->lineGap;
B
Behdad Esfahbod 已提交
93
      got_font_extents = (this->ascender | this->descender) != 0;
94
    }
B
Behdad Esfahbod 已提交
95 96
    hb_blob_destroy (_hea_blob);

B
Behdad Esfahbod 已提交
97 98
    this->has_font_extents = got_font_extents;

B
Minor  
Behdad Esfahbod 已提交
99
    this->blob = OT::Sanitizer<OT::hmtxvmtx>::sanitize (face->reference_table (_mtx_tag));
100 101 102

    /* Cap num_metrics() and num_advances() based on table length. */
    unsigned int len = hb_blob_get_length (this->blob);
103
    if (unlikely (this->num_advances * 4 > len))
104 105 106
      this->num_advances = len / 4;
    this->num_metrics = this->num_advances + (len - 4 * this->num_advances) / 2;

107
    /* We MUST set num_metrics to zero if num_advances is zero.
108 109
     * Our get_advance() depends on that. */
    if (unlikely (!this->num_advances))
B
Behdad Esfahbod 已提交
110
    {
111
      this->num_metrics = this->num_advances = 0;
B
Behdad Esfahbod 已提交
112 113 114
      hb_blob_destroy (this->blob);
      this->blob = hb_blob_get_empty ();
    }
B
Minor  
Behdad Esfahbod 已提交
115
    this->table = OT::Sanitizer<OT::hmtxvmtx>::lock_instance (this->blob);
116 117 118

    this->var_blob = OT::Sanitizer<OT::HVARVVAR>::sanitize (face->reference_table (_var_tag));
    this->var = OT::Sanitizer<OT::HVARVVAR>::lock_instance (this->var_blob);
B
Behdad Esfahbod 已提交
119 120 121 122 123
  }

  inline void fini (void)
  {
    hb_blob_destroy (this->blob);
124
    hb_blob_destroy (this->var_blob);
B
Behdad Esfahbod 已提交
125 126
  }

127 128
  inline unsigned int get_advance (hb_codepoint_t  glyph,
				   hb_font_t      *font) const
B
Behdad Esfahbod 已提交
129 130
  {
    if (unlikely (glyph >= this->num_metrics))
131 132
    {
      /* If this->num_metrics is zero, it means we don't have the metrics table
133 134
       * for this direction: return default advance.  Otherwise, it means that the
       * glyph index is out of bound: return zero. */
135 136 137 138 139
      if (this->num_metrics)
	return 0;
      else
	return this->default_advance;
    }
B
Behdad Esfahbod 已提交
140

141
    return this->table->longMetric[MIN (glyph, (uint32_t) this->num_advances - 1)].advance
142
	 + this->var->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
B
Behdad Esfahbod 已提交
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
struct hb_ot_face_glyf_accelerator_t
{
  bool short_offset;
  unsigned int num_glyphs;
  const OT::loca *loca;
  const OT::glyf *glyf;
  hb_blob_t *loca_blob;
  hb_blob_t *glyf_blob;
  unsigned int glyf_len;

  inline void init (hb_face_t *face)
  {
    hb_blob_t *head_blob = OT::Sanitizer<OT::head>::sanitize (face->reference_table (HB_OT_TAG_head));
    const OT::head *head = OT::Sanitizer<OT::head>::lock_instance (head_blob);
    if ((unsigned int) head->indexToLocFormat > 1 || head->glyphDataFormat != 0)
    {
      /* Unknown format.  Leave num_glyphs=0, that takes care of disabling us. */
      hb_blob_destroy (head_blob);
      return;
    }
    this->short_offset = 0 == head->indexToLocFormat;
    hb_blob_destroy (head_blob);

    this->loca_blob = OT::Sanitizer<OT::loca>::sanitize (face->reference_table (HB_OT_TAG_loca));
    this->loca = OT::Sanitizer<OT::loca>::lock_instance (this->loca_blob);
    this->glyf_blob = OT::Sanitizer<OT::glyf>::sanitize (face->reference_table (HB_OT_TAG_glyf));
    this->glyf = OT::Sanitizer<OT::glyf>::lock_instance (this->glyf_blob);

    this->num_glyphs = MAX (1u, hb_blob_get_length (this->loca_blob) / (this->short_offset ? 2 : 4)) - 1;
    this->glyf_len = hb_blob_get_length (this->glyf_blob);
  }

  inline void fini (void)
  {
    hb_blob_destroy (this->loca_blob);
    hb_blob_destroy (this->glyf_blob);
  }

  inline bool get_extents (hb_codepoint_t glyph,
			   hb_glyph_extents_t *extents) const
  {
    if (unlikely (glyph >= this->num_glyphs))
      return false;

    unsigned int start_offset, end_offset;
    if (this->short_offset)
    {
193 194
      start_offset = 2 * this->loca->u.shortsZ[glyph];
      end_offset   = 2 * this->loca->u.shortsZ[glyph + 1];
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
    }
    else
    {
      start_offset = this->loca->u.longsZ[glyph];
      end_offset   = this->loca->u.longsZ[glyph + 1];
    }

    if (start_offset > end_offset || end_offset > this->glyf_len)
      return false;

    if (end_offset - start_offset < OT::glyfGlyphHeader::static_size)
      return true; /* Empty glyph; zero extents. */

    const OT::glyfGlyphHeader &glyph_header = OT::StructAtOffset<OT::glyfGlyphHeader> (this->glyf, start_offset);

    extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax);
    extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax);
    extents->width     = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing;
    extents->height    = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing;

    return true;
  }
};

219
struct hb_ot_face_cbdt_accelerator_t
220
{
221 222 223 224
  hb_blob_t *cblc_blob;
  hb_blob_t *cbdt_blob;
  const OT::CBLC *cblc;
  const OT::CBDT *cbdt;
225

226
  unsigned int cbdt_len;
227
  unsigned int upem;
228 229 230

  inline void init (hb_face_t *face)
  {
231 232 233 234 235
    upem = face->get_upem();

    cblc_blob = OT::Sanitizer<OT::CBLC>::sanitize (face->reference_table (HB_OT_TAG_CBLC));
    cbdt_blob = OT::Sanitizer<OT::CBDT>::sanitize (face->reference_table (HB_OT_TAG_CBDT));
    cbdt_len = hb_blob_get_length (cbdt_blob);
236

237
    if (hb_blob_get_length (cblc_blob) == 0) {
238 239
      cblc = NULL;
      cbdt = NULL;
240 241
      return;  /* Not a bitmap font. */
    }
242 243
    cblc = OT::Sanitizer<OT::CBLC>::lock_instance (cblc_blob);
    cbdt = OT::Sanitizer<OT::CBDT>::lock_instance (cbdt_blob);
244 245 246 247 248

  }

  inline void fini (void)
  {
249 250
    hb_blob_destroy (this->cblc_blob);
    hb_blob_destroy (this->cbdt_blob);
251 252 253 254
  }

  inline bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
  {
255 256
    unsigned int x_ppem = upem, y_ppem = upem; /* TODO Use font ppem if available. */

257
    if (!cblc)
258 259
      return false;  // Not a color bitmap font.

260
    const OT::IndexSubtableRecord *subtable_record = this->cblc->find_table(glyph, &x_ppem, &y_ppem);
261
    if (!subtable_record || !x_ppem || !y_ppem)
262 263
      return false;

B
Behdad Esfahbod 已提交
264 265
    if (subtable_record->get_extents (extents))
      return true;
266

B
Behdad Esfahbod 已提交
267 268 269
    unsigned int image_offset = 0, image_length = 0, image_format = 0;
    if (!subtable_record->get_image_data (glyph, &image_offset, &image_length, &image_format))
      return false;
B
Behdad Esfahbod 已提交
270 271

    {
B
Behdad Esfahbod 已提交
272
      /* TODO Move the following into CBDT struct when adding more formats. */
273

B
Behdad Esfahbod 已提交
274
      if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
B
Behdad Esfahbod 已提交
275
	return false;
B
Behdad Esfahbod 已提交
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291

      switch (image_format)
      {
	case 17: {
	  if (unlikely (image_length < OT::GlyphBitmapDataFormat17::min_size))
	    return false;

	  const OT::GlyphBitmapDataFormat17& glyphFormat17 =
	      OT::StructAtOffset<OT::GlyphBitmapDataFormat17> (this->cbdt, image_offset);
	  glyphFormat17.glyphMetrics.get_extents (extents);
	}
	break;
	default:
	  // TODO: Support other image formats.
	  return false;
      }
292 293
    }

294
    /* Convert to the font units. */
295 296 297 298
    extents->x_bearing *= upem / (float) x_ppem;
    extents->y_bearing *= upem / (float) y_ppem;
    extents->width *= upem / (float) x_ppem;
    extents->height *= upem / (float) y_ppem;
299 300 301 302 303

    return true;
  }
};

304 305 306 307 308 309 310 311 312 313 314 315 316
typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj,
					  hb_codepoint_t codepoint,
					  hb_codepoint_t *glyph);

template <typename Type>
static inline bool get_glyph_from (const void *obj,
				   hb_codepoint_t codepoint,
				   hb_codepoint_t *glyph)
{
  const Type *typed_obj = (const Type *) obj;
  return typed_obj->get_glyph (codepoint, glyph);
}

317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
template <typename Type>
static inline bool get_glyph_from_symbol (const void *obj,
					  hb_codepoint_t codepoint,
					  hb_codepoint_t *glyph)
{
  const Type *typed_obj = (const Type *) obj;
  if (likely (typed_obj->get_glyph (codepoint, glyph)))
    return true;

  if (codepoint <= 0x00FFu)
  {
    /* For symbol-encoded OpenType fonts, we duplicate the
     * U+F000..F0FF range at U+0000..U+00FF.  That's what
     * Windows seems to do, and that's hinted about at:
     * http://www.microsoft.com/typography/otspec/recom.htm
     * under "Non-Standard (Symbol) Fonts". */
    return typed_obj->get_glyph (0xF000u + codepoint, glyph);
  }

  return false;
}

339 340
struct hb_ot_face_cmap_accelerator_t
{
341 342
  hb_cmap_get_glyph_func_t get_glyph_func;
  const void *get_glyph_data;
343
  OT::CmapSubtableFormat4::accelerator_t format4_accel;
344

345
  const OT::CmapSubtableFormat14 *uvs_table;
346 347 348 349 350 351 352
  hb_blob_t *blob;

  inline void init (hb_face_t *face)
  {
    this->blob = OT::Sanitizer<OT::cmap>::sanitize (face->reference_table (HB_OT_TAG_cmap));
    const OT::cmap *cmap = OT::Sanitizer<OT::cmap>::lock_instance (this->blob);
    const OT::CmapSubtable *subtable = NULL;
353
    const OT::CmapSubtableFormat14 *subtable_uvs = NULL;
354

355
    bool symbol = false;
356 357 358 359 360 361 362 363 364 365
    /* 32-bit subtables. */
    if (!subtable) subtable = cmap->find_subtable (3, 10);
    if (!subtable) subtable = cmap->find_subtable (0, 6);
    if (!subtable) subtable = cmap->find_subtable (0, 4);
    /* 16-bit subtables. */
    if (!subtable) subtable = cmap->find_subtable (3, 1);
    if (!subtable) subtable = cmap->find_subtable (0, 3);
    if (!subtable) subtable = cmap->find_subtable (0, 2);
    if (!subtable) subtable = cmap->find_subtable (0, 1);
    if (!subtable) subtable = cmap->find_subtable (0, 0);
366 367 368 369 370
    if (!subtable)
    {
      subtable = cmap->find_subtable (3, 0);
      if (subtable) symbol = true;
    }
371 372 373 374
    /* Meh. */
    if (!subtable) subtable = &OT::Null(OT::CmapSubtable);

    /* UVS subtable. */
375 376 377 378 379 380
    if (!subtable_uvs)
    {
      const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
      if (st && st->u.format == 14)
        subtable_uvs = &st->u.format14;
    }
381
    /* Meh. */
382
    if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
383 384

    this->uvs_table = subtable_uvs;
385 386

    this->get_glyph_data = subtable;
387 388 389 390 391 392 393 394 395 396 397 398 399 400
    if (unlikely (symbol))
      this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
    else
      switch (subtable->u.format) {
      /* Accelerate format 4 and format 12. */
      default: this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;		break;
      case 12: this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;	break;
      case  4:
	{
	  this->format4_accel.init (&subtable->u.format4);
	  this->get_glyph_data = &this->format4_accel;
	  this->get_glyph_func = this->format4_accel.get_glyph_func;
	}
	break;
401
      }
402 403 404 405 406 407 408
  }

  inline void fini (void)
  {
    hb_blob_destroy (this->blob);
  }

409 410
  inline bool get_nominal_glyph (hb_codepoint_t  unicode,
				 hb_codepoint_t *glyph) const
411
  {
412
    return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
413 414 415 416 417 418 419 420 421
  }

  inline bool get_variation_glyph (hb_codepoint_t  unicode,
				   hb_codepoint_t  variation_selector,
				   hb_codepoint_t *glyph) const
  {
    switch (this->uvs_table->get_glyph_variant (unicode,
						variation_selector,
						glyph))
422
    {
423 424 425
      case OT::GLYPH_VARIANT_NOT_FOUND:		return false;
      case OT::GLYPH_VARIANT_FOUND:		return true;
      case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
426 427
    }

428
    return get_nominal_glyph (unicode, glyph);
429 430 431
  }
};

432 433
struct hb_ot_font_t
{
434
  hb_ot_face_cmap_accelerator_t cmap;
B
Behdad Esfahbod 已提交
435 436
  hb_ot_face_metrics_accelerator_t h_metrics;
  hb_ot_face_metrics_accelerator_t v_metrics;
437 438
  OT::hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
  OT::hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
439 440 441 442
};


static hb_ot_font_t *
B
Minor  
Behdad Esfahbod 已提交
443
_hb_ot_font_create (hb_face_t *face)
444 445 446 447 448 449
{
  hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));

  if (unlikely (!ot_font))
    return NULL;

450
  ot_font->cmap.init (face);
451 452
  ot_font->h_metrics.init (face, HB_OT_TAG_hhea, HB_OT_TAG_hmtx, HB_OT_TAG_HVAR, HB_OT_TAG_os2);
  ot_font->v_metrics.init (face, HB_OT_TAG_vhea, HB_OT_TAG_vmtx, HB_OT_TAG_VVAR, HB_TAG_NONE,
453
			   ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
454
  ot_font->glyf.init (face);
455
  ot_font->cbdt.init (face);
456

457 458 459 460
  return ot_font;
}

static void
461
_hb_ot_font_destroy (void *data)
462
{
463 464
  hb_ot_font_t *ot_font = (hb_ot_font_t *) data;

465
  ot_font->cmap.fini ();
B
Behdad Esfahbod 已提交
466 467
  ot_font->h_metrics.fini ();
  ot_font->v_metrics.fini ();
B
Behdad Esfahbod 已提交
468
  ot_font->glyf.fini ();
469
  ot_font->cbdt.fini ();
470 471 472 473 474 475

  free (ot_font);
}


static hb_bool_t
476 477 478 479 480 481 482 483 484 485
hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED,
			 void *font_data,
			 hb_codepoint_t unicode,
			 hb_codepoint_t *glyph,
			 void *user_data HB_UNUSED)

{
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
  return ot_font->cmap.get_nominal_glyph (unicode, glyph);
}
486

487 488 489 490 491 492 493
static hb_bool_t
hb_ot_get_variation_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)
494
{
495
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
496
  return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph);
497 498 499
}

static hb_position_t
500
hb_ot_get_glyph_h_advance (hb_font_t *font,
501 502 503 504 505
			   void *font_data,
			   hb_codepoint_t glyph,
			   void *user_data HB_UNUSED)
{
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
506
  return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font));
507 508 509
}

static hb_position_t
510
hb_ot_get_glyph_v_advance (hb_font_t *font,
511 512 513 514
			   void *font_data,
			   hb_codepoint_t glyph,
			   void *user_data HB_UNUSED)
{
515
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
516
  return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font));
517 518 519 520 521 522 523 524 525
}

static hb_bool_t
hb_ot_get_glyph_extents (hb_font_t *font HB_UNUSED,
			 void *font_data,
			 hb_codepoint_t glyph,
			 hb_glyph_extents_t *extents,
			 void *user_data HB_UNUSED)
{
526
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
527
  bool ret = ot_font->glyf->get_extents (glyph, extents);
528
  if (!ret)
529
    ret = ot_font->cbdt->get_extents (glyph, extents);
530
  // TODO Hook up side-bearings variations.
531 532 533 534 535
  extents->x_bearing = font->em_scale_x (extents->x_bearing);
  extents->y_bearing = font->em_scale_y (extents->y_bearing);
  extents->width     = font->em_scale_x (extents->width);
  extents->height    = font->em_scale_y (extents->height);
  return ret;
536 537
}

538 539 540 541 542 543 544 545 546 547
static hb_bool_t
hb_ot_get_font_h_extents (hb_font_t *font HB_UNUSED,
			  void *font_data,
			  hb_font_extents_t *metrics,
			  void *user_data HB_UNUSED)
{
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
  metrics->ascender = font->em_scale_y (ot_font->h_metrics.ascender);
  metrics->descender = font->em_scale_y (ot_font->h_metrics.descender);
  metrics->line_gap = font->em_scale_y (ot_font->h_metrics.line_gap);
548
  // TODO Hook up variations.
B
Behdad Esfahbod 已提交
549
  return ot_font->h_metrics.has_font_extents;
550 551 552 553 554 555 556 557 558 559 560 561
}

static hb_bool_t
hb_ot_get_font_v_extents (hb_font_t *font HB_UNUSED,
			  void *font_data,
			  hb_font_extents_t *metrics,
			  void *user_data HB_UNUSED)
{
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
  metrics->ascender = font->em_scale_x (ot_font->v_metrics.ascender);
  metrics->descender = font->em_scale_x (ot_font->v_metrics.descender);
  metrics->line_gap = font->em_scale_x (ot_font->v_metrics.line_gap);
562
  // TODO Hook up variations.
B
Behdad Esfahbod 已提交
563
  return ot_font->v_metrics.has_font_extents;
564
}
565

566 567 568 569 570 571 572 573 574 575
static hb_font_funcs_t *static_ot_funcs = NULL;

#ifdef HB_USE_ATEXIT
static
void free_static_ot_funcs (void)
{
  hb_font_funcs_destroy (static_ot_funcs);
}
#endif

576 577 578
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
579 580
retry:
  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
581

582 583 584 585
  if (unlikely (!funcs))
  {
    funcs = hb_font_funcs_create ();

586 587
    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, NULL, NULL);
    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, NULL, NULL);
588 589
    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, NULL, NULL);
    hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, NULL, NULL);
590 591
    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, NULL, NULL);
    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, NULL, NULL);
592 593 594 595
    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, NULL, NULL);
    //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, NULL, NULL);
    //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, NULL, NULL); TODO
    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, NULL, NULL);
596
    hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, NULL, NULL);
597 598 599
    //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, NULL, NULL); TODO
    //hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, NULL, NULL); TODO
    //hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, NULL, NULL); TODO
600 601 602 603 604 605

    hb_font_funcs_make_immutable (funcs);

    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, NULL, funcs)) {
      hb_font_funcs_destroy (funcs);
      goto retry;
606
    }
607 608 609 610

#ifdef HB_USE_ATEXIT
    atexit (free_static_ot_funcs); /* First person registers atexit() callback. */
#endif
611 612
  };

613
  return funcs;
614 615 616
}


S
Sascha Brawer 已提交
617
/**
B
Behdad Esfahbod 已提交
618 619
 * hb_ot_font_set_funcs:
 *
S
Sascha Brawer 已提交
620 621
 * Since: 0.9.28
 **/
622 623 624
void
hb_ot_font_set_funcs (hb_font_t *font)
{
B
Minor  
Behdad Esfahbod 已提交
625
  hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
626 627 628 629 630 631
  if (unlikely (!ot_font))
    return;

  hb_font_set_funcs (font,
		     _hb_ot_get_font_funcs (),
		     ot_font,
632
		     _hb_ot_font_destroy);
633
}