hb-ot-font.cc 21.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-os2-table.hh"
40
#include "hb-ot-post-table.hh"
B
Behdad Esfahbod 已提交
41
#include "hb-ot-var-hvar-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) {
B
Behdad Esfahbod 已提交
238 239
      cblc = nullptr;
      cbdt = nullptr;
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
struct hb_ot_face_post_accelerator_t
{
  hb_blob_t *post_blob;
B
Behdad Esfahbod 已提交
307
  OT::post::accelerator_t accel;
308 309 310

  inline void init (hb_face_t *face)
  {
B
Behdad Esfahbod 已提交
311 312
    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));
313 314 315 316
  }

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

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

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

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

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

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

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

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

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

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

    this->uvs_table = subtable_uvs;
418 419

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

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

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

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

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

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


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

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

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

492 493 494 495
  return ot_font;
}

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

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

  free (ot_font);
}


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

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

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

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

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

574 575 576 577 578 579 580 581 582 583 584
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);
}

585 586 587 588 589 590 591 592 593 594 595
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);
}

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
645 646 647 648 649 650 651 652 653 654 655 656
    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
657
    hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
658
    hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
659 660

    hb_font_funcs_make_immutable (funcs);
661
    hb_object_make_inert (funcs);
662

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

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

674
  return funcs;
675 676 677
}


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

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