hb-ot-font.cc 21.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-kern-table.hh"
40
#include "hb-ot-os2-table.hh"
41
#include "hb-ot-post-table.hh"
B
Behdad Esfahbod 已提交
42
#include "hb-ot-var-hvar-table.hh"
43 44


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

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

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

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

70 71 72 73 74
    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);
75 76 77 78 79 80 81 82
#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;
      }
83 84 85
      hb_blob_destroy (os2_blob);
    }

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

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

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

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

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

    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 已提交
120 121 122 123 124
  }

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

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

142
    return this->table->longMetric[MIN (glyph, (uint32_t) this->num_advances - 1)].advance
143
	 + this->var->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
B
Behdad Esfahbod 已提交
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
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)
    {
194 195
      start_offset = 2 * this->loca->u.shortsZ[glyph];
      end_offset   = 2 * this->loca->u.shortsZ[glyph + 1];
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
    }
    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;
  }
};

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

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

  inline void init (hb_face_t *face)
  {
232 233 234 235 236
    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);
237

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

  }

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

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

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

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

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

B
Behdad Esfahbod 已提交
268 269 270
    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 已提交
271 272

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

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

      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;
      }
293 294
    }

295
    /* Convert to the font units. */
296 297 298 299
    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;
300 301 302 303 304

    return true;
  }
};

305 306 307
struct hb_ot_face_post_accelerator_t
{
  hb_blob_t *post_blob;
B
Behdad Esfahbod 已提交
308
  OT::post::accelerator_t accel;
309 310 311

  inline void init (hb_face_t *face)
  {
B
Behdad Esfahbod 已提交
312 313
    hb_blob_t *blob = this->post_blob = OT::Sanitizer<OT::post>::sanitize (face->reference_table (HB_OT_TAG_post));
    accel.init (OT::Sanitizer<OT::post>::lock_instance (blob), hb_blob_get_length (blob));
314 315 316 317
  }

  inline void fini (void)
  {
B
Behdad Esfahbod 已提交
318
    accel.fini ();
319 320 321 322
    hb_blob_destroy (this->post_blob);
  }

  inline bool get_glyph_name (hb_codepoint_t glyph,
B
Behdad Esfahbod 已提交
323
			      char *name, unsigned int size) const
324
  {
B
Behdad Esfahbod 已提交
325
    return this->accel.get_glyph_name (glyph, name, size);
326
  }
327 328

  inline bool get_glyph_from_name (const char *name, int len,
B
Behdad Esfahbod 已提交
329
				   hb_codepoint_t *glyph) const
330
  {
B
Behdad Esfahbod 已提交
331
    if (unlikely (!len))
332 333
      return false;

B
Behdad Esfahbod 已提交
334
    return this->accel.get_glyph_from_name (name, len, glyph);
335
  }
336 337
};

338 339 340 341 342 343 344 345 346 347 348 349 350
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);
}

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372
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;
}

373 374
struct hb_ot_face_cmap_accelerator_t
{
375 376
  hb_cmap_get_glyph_func_t get_glyph_func;
  const void *get_glyph_data;
377
  OT::CmapSubtableFormat4::accelerator_t format4_accel;
378

379
  const OT::CmapSubtableFormat14 *uvs_table;
380 381 382 383 384 385
  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);
B
Behdad Esfahbod 已提交
386 387
    const OT::CmapSubtable *subtable = nullptr;
    const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
388

389
    bool symbol = false;
390 391 392 393 394 395 396 397 398 399
    /* 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);
400 401 402 403 404
    if (!subtable)
    {
      subtable = cmap->find_subtable (3, 0);
      if (subtable) symbol = true;
    }
405 406 407 408
    /* Meh. */
    if (!subtable) subtable = &OT::Null(OT::CmapSubtable);

    /* UVS subtable. */
409 410 411 412 413 414
    if (!subtable_uvs)
    {
      const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
      if (st && st->u.format == 14)
        subtable_uvs = &st->u.format14;
    }
415
    /* Meh. */
416
    if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
417 418

    this->uvs_table = subtable_uvs;
419 420

    this->get_glyph_data = subtable;
421 422 423 424 425 426 427 428 429 430 431 432 433 434
    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;
435
      }
436 437 438 439 440 441 442
  }

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

443 444
  inline bool get_nominal_glyph (hb_codepoint_t  unicode,
				 hb_codepoint_t *glyph) const
445
  {
446
    return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
447 448 449 450 451 452 453 454 455
  }

  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))
456
    {
457 458 459
      case OT::GLYPH_VARIANT_NOT_FOUND:		return false;
      case OT::GLYPH_VARIANT_FOUND:		return true;
      case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
460 461
    }

462
    return get_nominal_glyph (unicode, glyph);
463 464 465
  }
};

466 467
struct hb_ot_font_t
{
468
  hb_ot_face_cmap_accelerator_t cmap;
B
Behdad Esfahbod 已提交
469 470
  hb_ot_face_metrics_accelerator_t h_metrics;
  hb_ot_face_metrics_accelerator_t v_metrics;
471 472
  OT::hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
  OT::hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
473
  OT::hb_lazy_loader_t<hb_ot_face_post_accelerator_t> post;
474 475 476 477
};


static hb_ot_font_t *
B
Minor  
Behdad Esfahbod 已提交
478
_hb_ot_font_create (hb_face_t *face)
479 480 481 482
{
  hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));

  if (unlikely (!ot_font))
B
Behdad Esfahbod 已提交
483
    return nullptr;
484

485
  ot_font->cmap.init (face);
486 487
  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,
488
			   ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
489
  ot_font->glyf.init (face);
490
  ot_font->cbdt.init (face);
491
  ot_font->post.init (face);
492

493 494 495 496
  return ot_font;
}

static void
497
_hb_ot_font_destroy (void *data)
498
{
499 500
  hb_ot_font_t *ot_font = (hb_ot_font_t *) data;

501
  ot_font->cmap.fini ();
B
Behdad Esfahbod 已提交
502 503
  ot_font->h_metrics.fini ();
  ot_font->v_metrics.fini ();
B
Behdad Esfahbod 已提交
504
  ot_font->glyf.fini ();
505
  ot_font->cbdt.fini ();
506
  ot_font->post.fini ();
507 508 509 510 511 512

  free (ot_font);
}


static hb_bool_t
513 514 515 516 517 518 519 520 521 522
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);
}
523

524 525 526 527 528 529 530
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)
531
{
532
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
533
  return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph);
534 535 536
}

static hb_position_t
537
hb_ot_get_glyph_h_advance (hb_font_t *font,
538 539 540 541 542
			   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;
543
  return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font));
544 545 546
}

static hb_position_t
547
hb_ot_get_glyph_v_advance (hb_font_t *font,
548 549 550 551
			   void *font_data,
			   hb_codepoint_t glyph,
			   void *user_data HB_UNUSED)
{
552
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
553
  return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font));
554 555 556 557 558 559 560 561 562
}

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)
{
563
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
564
  bool ret = ot_font->glyf->get_extents (glyph, extents);
565
  if (!ret)
566
    ret = ot_font->cbdt->get_extents (glyph, extents);
567
  // TODO Hook up side-bearings variations.
568 569 570 571 572
  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;
573 574
}

575 576 577 578 579 580 581 582 583 584 585
static hb_bool_t
hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
                      void *font_data,
                      hb_codepoint_t glyph,
                      char *name, unsigned int size,
                      void *user_data HB_UNUSED)
{
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
  return ot_font->post->get_glyph_name (glyph, name, size);
}

586 587 588 589 590 591 592 593 594 595 596
static hb_bool_t
hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
                           void *font_data,
                           const char *name, int len,
                           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->post->get_glyph_from_name (name, len, glyph);
}

597 598 599 600 601 602 603 604 605 606
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);
607
  // TODO Hook up variations.
B
Behdad Esfahbod 已提交
608
  return ot_font->h_metrics.has_font_extents;
609 610 611 612 613 614 615 616 617 618 619 620
}

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);
621
  // TODO Hook up variations.
B
Behdad Esfahbod 已提交
622
  return ot_font->v_metrics.has_font_extents;
623
}
624

B
Behdad Esfahbod 已提交
625
static hb_font_funcs_t *static_ot_funcs = nullptr;
626 627 628 629 630

#ifdef HB_USE_ATEXIT
static
void free_static_ot_funcs (void)
{
631
  hb_object_undo_inert (static_ot_funcs);
632 633 634 635
  hb_font_funcs_destroy (static_ot_funcs);
}
#endif

636 637 638
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
639 640
retry:
  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
641

642 643 644 645
  if (unlikely (!funcs))
  {
    funcs = hb_font_funcs_create ();

B
Behdad Esfahbod 已提交
646 647 648 649 650 651 652 653 654 655 656 657
    hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr);
    hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr);
    hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr);
    hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr);
    hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ot_get_glyph_h_advance, nullptr, nullptr);
    hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ot_get_glyph_v_advance, nullptr, nullptr);
    //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr);
    //hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
    //hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, nullptr, nullptr); TODO
    //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ot_get_glyph_v_kerning, nullptr, nullptr);
    hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
    //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr); TODO
658
    hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
659
    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
660 661

    hb_font_funcs_make_immutable (funcs);
662
    hb_object_make_inert (funcs);
663

B
Behdad Esfahbod 已提交
664
    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, nullptr, funcs)) {
665
      hb_object_undo_inert (funcs);
666 667
      hb_font_funcs_destroy (funcs);
      goto retry;
668
    }
669 670 671 672

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

675
  return funcs;
676 677 678
}


S
Sascha Brawer 已提交
679
/**
B
Behdad Esfahbod 已提交
680 681
 * hb_ot_font_set_funcs:
 *
S
Sascha Brawer 已提交
682 683
 * Since: 0.9.28
 **/
684 685 686
void
hb_ot_font_set_funcs (hb_font_t *font)
{
B
Minor  
Behdad Esfahbod 已提交
687
  hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
688 689 690 691 692 693
  if (unlikely (!ot_font))
    return;

  hb_font_set_funcs (font,
		     _hb_ot_get_font_funcs (),
		     ot_font,
694
		     _hb_ot_font_destroy);
695
}