hb-ot-font.cc 22.0 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;
B
Behdad Esfahbod 已提交
474
  OT::hb_lazy_table_loader_t<OT::kern> kern;
475 476 477 478
};


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

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

486
  ot_font->cmap.init (face);
487 488
  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,
489
			   ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
490
  ot_font->glyf.init (face);
491
  ot_font->cbdt.init (face);
492
  ot_font->post.init (face);
B
Behdad Esfahbod 已提交
493
  ot_font->kern.init (face);
494

495 496 497 498
  return ot_font;
}

static void
499
_hb_ot_font_destroy (void *data)
500
{
501 502
  hb_ot_font_t *ot_font = (hb_ot_font_t *) data;

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

  free (ot_font);
}


static hb_bool_t
516 517 518 519 520 521 522 523 524 525
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);
}
526

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

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

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

B
Behdad Esfahbod 已提交
559 560 561 562 563 564 565 566 567 568 569
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));
}

570 571 572 573 574 575 576
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)
{
577
  const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data;
578
  bool ret = ot_font->glyf->get_extents (glyph, extents);
579
  if (!ret)
580
    ret = ot_font->cbdt->get_extents (glyph, extents);
581
  // TODO Hook up side-bearings variations.
582 583 584 585 586
  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;
587 588
}

589 590 591 592 593 594 595 596 597 598 599
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);
}

600 601 602 603 604 605 606 607 608 609 610
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);
}

611 612 613 614 615 616 617 618 619 620
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);
621
  // TODO Hook up variations.
B
Behdad Esfahbod 已提交
622
  return ot_font->h_metrics.has_font_extents;
623 624 625 626 627 628 629 630 631 632 633 634
}

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);
635
  // TODO Hook up variations.
B
Behdad Esfahbod 已提交
636
  return ot_font->v_metrics.has_font_extents;
637
}
638

B
Behdad Esfahbod 已提交
639
static hb_font_funcs_t *static_ot_funcs = nullptr;
640 641 642 643 644

#ifdef HB_USE_ATEXIT
static
void free_static_ot_funcs (void)
{
645
  hb_object_undo_inert (static_ot_funcs);
646 647 648 649
  hb_font_funcs_destroy (static_ot_funcs);
}
#endif

650 651 652
static hb_font_funcs_t *
_hb_ot_get_font_funcs (void)
{
653 654
retry:
  hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ot_funcs);
655

656 657 658 659
  if (unlikely (!funcs))
  {
    funcs = hb_font_funcs_create ();

B
Behdad Esfahbod 已提交
660 661 662 663 664 665 666 667
    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);
668
    hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ot_get_glyph_h_kerning, nullptr, nullptr);
B
Behdad Esfahbod 已提交
669 670 671
    //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
672
    hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
673
    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
674 675

    hb_font_funcs_make_immutable (funcs);
676
    hb_object_make_inert (funcs);
677

B
Behdad Esfahbod 已提交
678
    if (!hb_atomic_ptr_cmpexch (&static_ot_funcs, nullptr, funcs)) {
679
      hb_object_undo_inert (funcs);
680 681
      hb_font_funcs_destroy (funcs);
      goto retry;
682
    }
683 684 685 686

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

689
  return funcs;
690 691 692
}


S
Sascha Brawer 已提交
693
/**
B
Behdad Esfahbod 已提交
694 695
 * hb_ot_font_set_funcs:
 *
S
Sascha Brawer 已提交
696 697
 * Since: 0.9.28
 **/
698 699 700
void
hb_ot_font_set_funcs (hb_font_t *font)
{
B
Minor  
Behdad Esfahbod 已提交
701
  hb_ot_font_t *ot_font = _hb_ot_font_create (font->face);
702 703 704 705 706 707
  if (unlikely (!ot_font))
    return;

  hb_font_set_funcs (font,
		     _hb_ot_get_font_funcs (),
		     ot_font,
708
		     _hb_ot_font_destroy);
709
}