hb-ot-font.cc 22.5 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 351 352 353 354 355 356 357 358
struct hb_ot_face_kern_accelerator_t
{
  hb_blob_t *kern_blob;
  OT::kern::accelerator_t accel;

  inline void init (hb_face_t *face)
  {
    hb_blob_t *blob = this->kern_blob = OT::Sanitizer<OT::kern>::sanitize (face->reference_table (HB_OT_TAG_kern));
    accel.init (OT::Sanitizer<OT::kern>::lock_instance (blob), hb_blob_get_length (blob));
  }

  inline void fini (void)
  {
    accel.fini ();
    hb_blob_destroy (this->kern_blob);
  }

  inline int get_h_kerning (hb_codepoint_t left, hb_codepoint_t right) const
  { return accel.get_h_kerning (left, right); }
};

359 360 361 362 363 364 365 366 367 368 369 370 371
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);
}

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
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;
}

394 395
struct hb_ot_face_cmap_accelerator_t
{
396 397
  hb_cmap_get_glyph_func_t get_glyph_func;
  const void *get_glyph_data;
398
  OT::CmapSubtableFormat4::accelerator_t format4_accel;
399

400
  const OT::CmapSubtableFormat14 *uvs_table;
401 402 403 404 405 406
  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 已提交
407 408
    const OT::CmapSubtable *subtable = nullptr;
    const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
409

410
    bool symbol = false;
411 412 413 414 415 416 417 418 419 420
    /* 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);
421 422 423 424 425
    if (!subtable)
    {
      subtable = cmap->find_subtable (3, 0);
      if (subtable) symbol = true;
    }
426 427 428 429
    /* Meh. */
    if (!subtable) subtable = &OT::Null(OT::CmapSubtable);

    /* UVS subtable. */
430 431 432 433 434 435
    if (!subtable_uvs)
    {
      const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
      if (st && st->u.format == 14)
        subtable_uvs = &st->u.format14;
    }
436
    /* Meh. */
437
    if (!subtable_uvs) subtable_uvs = &OT::Null(OT::CmapSubtableFormat14);
438 439

    this->uvs_table = subtable_uvs;
440 441

    this->get_glyph_data = subtable;
442 443 444 445 446 447 448 449 450 451 452 453 454 455
    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;
456
      }
457 458 459 460 461 462 463
  }

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

464 465
  inline bool get_nominal_glyph (hb_codepoint_t  unicode,
				 hb_codepoint_t *glyph) const
466
  {
467
    return this->get_glyph_func (this->get_glyph_data, unicode, glyph);
468 469 470 471 472 473 474 475 476
  }

  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))
477
    {
478 479 480
      case OT::GLYPH_VARIANT_NOT_FOUND:		return false;
      case OT::GLYPH_VARIANT_FOUND:		return true;
      case OT::GLYPH_VARIANT_USE_DEFAULT:	break;
481 482
    }

483
    return get_nominal_glyph (unicode, glyph);
484 485 486
  }
};

487 488
struct hb_ot_font_t
{
489
  hb_ot_face_cmap_accelerator_t cmap;
B
Behdad Esfahbod 已提交
490 491
  hb_ot_face_metrics_accelerator_t h_metrics;
  hb_ot_face_metrics_accelerator_t v_metrics;
492 493
  OT::hb_lazy_loader_t<hb_ot_face_glyf_accelerator_t> glyf;
  OT::hb_lazy_loader_t<hb_ot_face_cbdt_accelerator_t> cbdt;
494
  OT::hb_lazy_loader_t<hb_ot_face_post_accelerator_t> post;
495
  OT::hb_lazy_loader_t<hb_ot_face_kern_accelerator_t> kern;
496 497 498 499
};


static hb_ot_font_t *
B
Minor  
Behdad Esfahbod 已提交
500
_hb_ot_font_create (hb_face_t *face)
501 502 503 504
{
  hb_ot_font_t *ot_font = (hb_ot_font_t *) calloc (1, sizeof (hb_ot_font_t));

  if (unlikely (!ot_font))
B
Behdad Esfahbod 已提交
505
    return nullptr;
506

507
  ot_font->cmap.init (face);
508 509
  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,
510
			   ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
511
  ot_font->glyf.init (face);
512
  ot_font->cbdt.init (face);
513
  ot_font->post.init (face);
B
Behdad Esfahbod 已提交
514
  ot_font->kern.init (face);
515

516 517 518 519
  return ot_font;
}

static void
520
_hb_ot_font_destroy (void *data)
521
{
522 523
  hb_ot_font_t *ot_font = (hb_ot_font_t *) data;

524
  ot_font->cmap.fini ();
B
Behdad Esfahbod 已提交
525 526
  ot_font->h_metrics.fini ();
  ot_font->v_metrics.fini ();
B
Behdad Esfahbod 已提交
527
  ot_font->glyf.fini ();
528
  ot_font->cbdt.fini ();
529
  ot_font->post.fini ();
B
Behdad Esfahbod 已提交
530
  ot_font->kern.fini ();
531 532 533 534 535 536

  free (ot_font);
}


static hb_bool_t
537 538 539 540 541 542 543 544 545 546
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);
}
547

548 549 550 551 552 553 554
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)
555
{
556
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
557
  return ot_font->cmap.get_variation_glyph (unicode, variation_selector, glyph);
558 559 560
}

static hb_position_t
561
hb_ot_get_glyph_h_advance (hb_font_t *font,
562 563 564 565 566
			   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;
567
  return font->em_scale_x (ot_font->h_metrics.get_advance (glyph, font));
568 569 570
}

static hb_position_t
571
hb_ot_get_glyph_v_advance (hb_font_t *font,
572 573 574 575
			   void *font_data,
			   hb_codepoint_t glyph,
			   void *user_data HB_UNUSED)
{
576
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
577
  return font->em_scale_y (-(int) ot_font->v_metrics.get_advance (glyph, font));
578 579
}

B
Behdad Esfahbod 已提交
580 581 582 583 584 585 586 587 588 589 590
static hb_position_t
hb_ot_get_glyph_h_kerning (hb_font_t *font,
			   void *font_data,
			   hb_codepoint_t left_glyph,
			   hb_codepoint_t right_glyph,
			   void *user_data HB_UNUSED)
{
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
  return font->em_scale_x (ot_font->kern->get_h_kerning (left_glyph, right_glyph));
}

591 592 593 594 595 596 597
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)
{
598
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
599
  bool ret = ot_font->glyf->get_extents (glyph, extents);
600
  if (!ret)
601
    ret = ot_font->cbdt->get_extents (glyph, extents);
602
  // TODO Hook up side-bearings variations.
603 604 605 606 607
  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;
608 609
}

610 611 612 613 614 615 616 617 618 619 620
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);
}

621 622 623 624 625 626 627 628 629 630 631
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);
}

632 633 634 635 636 637 638 639 640 641
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);
642
  // TODO Hook up variations.
B
Behdad Esfahbod 已提交
643
  return ot_font->h_metrics.has_font_extents;
644 645 646 647 648 649 650 651 652 653 654 655
}

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);
656
  // TODO Hook up variations.
B
Behdad Esfahbod 已提交
657
  return ot_font->v_metrics.has_font_extents;
658
}
659

B
Behdad Esfahbod 已提交
660
static hb_font_funcs_t *static_ot_funcs = nullptr;
661 662 663 664 665 666 667 668 669

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

670 671 672
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
673 674
retry:
  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
675

676 677 678 679
  if (unlikely (!funcs))
  {
    funcs = hb_font_funcs_create ();

B
Behdad Esfahbod 已提交
680 681 682 683 684 685 686 687
    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);
688
    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, nullptr, nullptr);
B
Behdad Esfahbod 已提交
689 690 691
    //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
692
    hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
693
    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
694 695 696

    hb_font_funcs_make_immutable (funcs);

B
Behdad Esfahbod 已提交
697
    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, nullptr, funcs)) {
698 699
      hb_font_funcs_destroy (funcs);
      goto retry;
700
    }
701 702 703 704

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

707
  return funcs;
708 709 710
}


S
Sascha Brawer 已提交
711
/**
B
Behdad Esfahbod 已提交
712 713
 * hb_ot_font_set_funcs:
 *
S
Sascha Brawer 已提交
714 715
 * Since: 0.9.28
 **/
716 717 718
void
hb_ot_font_set_funcs (hb_font_t *font)
{
B
Minor  
Behdad Esfahbod 已提交
719
  hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
720 721 722 723 724 725
  if (unlikely (!ot_font))
    return;

  hb_font_set_funcs (font,
		     _hb_ot_get_font_funcs (),
		     ot_font,
726
		     _hb_ot_font_destroy);
727
}