hb-ot-layout.cc 19.9 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2 3 4
 * Copyright © 1998-2004  David Turner and Werner Lemberg
 * Copyright © 2006  Behdad Esfahbod
 * Copyright © 2007,2008,2009  Red Hat, Inc.
B
Behdad Esfahbod 已提交
5
 * Copyright © 2012  Google, Inc.
B
Behdad Esfahbod 已提交
6
 *
B
Behdad Esfahbod 已提交
7
 *  This is part of HarfBuzz, a text shaping library.
B
Behdad Esfahbod 已提交
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * 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.
 *
 * Red Hat Author(s): Behdad Esfahbod
B
Behdad Esfahbod 已提交
28
 * Google Author(s): Behdad Esfahbod
B
Behdad Esfahbod 已提交
29 30
 */

31
#include "hb-ot-layout-private.hh"
B
Behdad Esfahbod 已提交
32

33 34 35 36
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
#include "hb-ot-maxp-table.hh"
B
Behdad Esfahbod 已提交
37 38

#include <stdlib.h>
B
Behdad Esfahbod 已提交
39 40
#include <string.h>

B
Behdad Esfahbod 已提交
41

42
HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
43

B
Behdad Esfahbod 已提交
44
hb_ot_layout_t *
45
_hb_ot_layout_create (hb_face_t *face)
46
{
B
Behdad Esfahbod 已提交
47
  hb_ot_layout_t *layout = (hb_ot_layout_t *) calloc (1, sizeof (hb_ot_layout_t));
B
Minor  
Behdad Esfahbod 已提交
48 49
  if (unlikely (!layout))
    return NULL;
50

51 52
  layout->gdef_blob = OT::Sanitizer<OT::GDEF>::sanitize (face->reference_table (HB_OT_TAG_GDEF));
  layout->gdef = OT::Sanitizer<OT::GDEF>::lock_instance (layout->gdef_blob);
B
Behdad Esfahbod 已提交
53

54 55
  layout->gsub_blob = OT::Sanitizer<OT::GSUB>::sanitize (face->reference_table (HB_OT_TAG_GSUB));
  layout->gsub = OT::Sanitizer<OT::GSUB>::lock_instance (layout->gsub_blob);
B
Behdad Esfahbod 已提交
56

57 58
  layout->gpos_blob = OT::Sanitizer<OT::GPOS>::sanitize (face->reference_table (HB_OT_TAG_GPOS));
  layout->gpos = OT::Sanitizer<OT::GPOS>::lock_instance (layout->gpos_blob);
B
Behdad Esfahbod 已提交
59

60 61 62
  layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
  layout->gpos_lookup_count = layout->gpos->get_lookup_count ();

63 64 65
  layout->gsub_digests = (hb_set_digest_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_set_digest_t));
  layout->gpos_digests = (hb_set_digest_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_set_digest_t));

66 67
  if (unlikely ((layout->gsub_lookup_count && !layout->gsub_digests) ||
		(layout->gpos_lookup_count && !layout->gpos_digests)))
68 69 70 71 72
  {
    _hb_ot_layout_destroy (layout);
    return NULL;
  }

73
  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
74
    layout->gsub->add_coverage (&layout->gsub_digests[i], i);
75
  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
76 77
    layout->gpos->add_coverage (&layout->gpos_digests[i], i);

B
Behdad Esfahbod 已提交
78
  return layout;
B
Behdad Esfahbod 已提交
79 80
}

81
void
82
_hb_ot_layout_destroy (hb_ot_layout_t *layout)
B
Behdad Esfahbod 已提交
83
{
B
Behdad Esfahbod 已提交
84 85 86
  hb_blob_destroy (layout->gdef_blob);
  hb_blob_destroy (layout->gsub_blob);
  hb_blob_destroy (layout->gpos_blob);
B
Behdad Esfahbod 已提交
87

88 89 90
  free (layout->gsub_digests);
  free (layout->gpos_digests);

B
Behdad Esfahbod 已提交
91
  free (layout);
92
}
B
Behdad Esfahbod 已提交
93

94
static inline const OT::GDEF&
95 96
_get_gdef (hb_face_t *face)
{
97
  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GDEF);
98
  return *hb_ot_layout_from_face (face)->gdef;
99
}
100
static inline const OT::GSUB&
101
_get_gsub (hb_face_t *face)
B
Behdad Esfahbod 已提交
102
{
103
  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GSUB);
104
  return *hb_ot_layout_from_face (face)->gsub;
B
Behdad Esfahbod 已提交
105
}
106
static inline const OT::GPOS&
107
_get_gpos (hb_face_t *face)
B
Behdad Esfahbod 已提交
108
{
109
  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return OT::Null(OT::GPOS);
110
  return *hb_ot_layout_from_face (face)->gpos;
B
Behdad Esfahbod 已提交
111 112
}

113

B
Behdad Esfahbod 已提交
114 115 116 117 118
/*
 * GDEF
 */

hb_bool_t
119
hb_ot_layout_has_glyph_classes (hb_face_t *face)
B
Behdad Esfahbod 已提交
120
{
121
  return _get_gdef (face).has_glyph_classes ();
B
Behdad Esfahbod 已提交
122 123
}

124 125 126 127 128 129
hb_ot_layout_glyph_class_t
hb_ot_layout_get_glyph_class (hb_face_t      *face,
			      hb_codepoint_t  glyph)
{
  return (hb_ot_layout_glyph_class_t) _get_gdef (face).get_glyph_class (glyph);
}
B
Behdad Esfahbod 已提交
130

131 132 133 134 135 136 137 138
void
hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
				  hb_ot_layout_glyph_class_t  klass,
				  hb_set_t                   *glyphs /* OUT */)
{
  return _get_gdef (face).get_glyphs_in_class (klass, glyphs);
}

B
Behdad Esfahbod 已提交
139
unsigned int
140
hb_ot_layout_get_attach_points (hb_face_t      *face,
B
Behdad Esfahbod 已提交
141
				hb_codepoint_t  glyph,
B
Behdad Esfahbod 已提交
142
				unsigned int    start_offset,
B
Behdad Esfahbod 已提交
143 144 145
				unsigned int   *point_count /* IN/OUT */,
				unsigned int   *point_array /* OUT */)
{
B
Behdad Esfahbod 已提交
146
  return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
B
Behdad Esfahbod 已提交
147 148
}

B
Behdad Esfahbod 已提交
149
unsigned int
150 151 152 153 154 155
hb_ot_layout_get_ligature_carets (hb_font_t      *font,
				  hb_direction_t  direction,
				  hb_codepoint_t  glyph,
				  unsigned int    start_offset,
				  unsigned int   *caret_count /* IN/OUT */,
				  int            *caret_array /* OUT */)
B
Behdad Esfahbod 已提交
156
{
157
  return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
B
Behdad Esfahbod 已提交
158 159
}

160

161 162 163 164
/*
 * GSUB/GPOS
 */

165
static const OT::GSUBGPOS&
166 167
get_gsubgpos_table (hb_face_t *face,
		    hb_tag_t   table_tag)
168
{
169
  switch (table_tag) {
170 171
    case HB_OT_TAG_GSUB: return _get_gsub (face);
    case HB_OT_TAG_GPOS: return _get_gpos (face);
172
    default:             return OT::Null(OT::GSUBGPOS);
173 174 175 176
  }
}


B
Behdad Esfahbod 已提交
177
unsigned int
178 179
hb_ot_layout_table_get_script_tags (hb_face_t    *face,
				    hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
180
				    unsigned int  start_offset,
181 182
				    unsigned int *script_count /* IN/OUT */,
				    hb_tag_t     *script_tags /* OUT */)
183
{
184
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
185

B
Behdad Esfahbod 已提交
186
  return g.get_script_tags (start_offset, script_count, script_tags);
187 188 189
}

hb_bool_t
190 191 192 193
hb_ot_layout_table_find_script (hb_face_t    *face,
				hb_tag_t      table_tag,
				hb_tag_t      script_tag,
				unsigned int *script_index)
194
{
195 196
  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
197 198

  if (g.find_script_index (script_tag, script_index))
199
    return true;
200 201

  /* try finding 'DFLT' */
202
  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
203
    return false;
204

205 206
  /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
   * including many versions of DejaVu Sans Mono! */
207
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
208
    return false;
B
Behdad Esfahbod 已提交
209 210

  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
211
  return false;
B
Behdad Esfahbod 已提交
212 213 214 215 216 217
}

hb_bool_t
hb_ot_layout_table_choose_script (hb_face_t      *face,
				  hb_tag_t        table_tag,
				  const hb_tag_t *script_tags,
B
Behdad Esfahbod 已提交
218 219
				  unsigned int   *script_index,
				  hb_tag_t       *chosen_script)
B
Behdad Esfahbod 已提交
220
{
221 222
  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
B
Behdad Esfahbod 已提交
223 224 225

  while (*script_tags)
  {
B
Behdad Esfahbod 已提交
226 227 228
    if (g.find_script_index (*script_tags, script_index)) {
      if (chosen_script)
        *chosen_script = *script_tags;
229
      return true;
B
Behdad Esfahbod 已提交
230
    }
B
Behdad Esfahbod 已提交
231 232 233 234
    script_tags++;
  }

  /* try finding 'DFLT' */
B
Behdad Esfahbod 已提交
235 236 237
  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
238
    return false;
B
Behdad Esfahbod 已提交
239
  }
B
Behdad Esfahbod 已提交
240 241

  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
B
Behdad Esfahbod 已提交
242 243 244
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
245
    return false;
B
Behdad Esfahbod 已提交
246
  }
247

248 249 250 251 252 253
  /* try with 'latn'; some old fonts put their features there even though
     they're really trying to support Thai, for example :( */
#define HB_OT_TAG_LATIN_SCRIPT		HB_TAG ('l', 'a', 't', 'n')
  if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
254
    return false;
255 256
  }

257
  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
B
Behdad Esfahbod 已提交
258 259
  if (chosen_script)
    *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
260
  return false;
261 262
}

B
Behdad Esfahbod 已提交
263
unsigned int
264 265
hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
				     hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
266
				     unsigned int  start_offset,
267 268
				     unsigned int *feature_count /* IN/OUT */,
				     hb_tag_t     *feature_tags /* OUT */)
269
{
270
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
271

B
Behdad Esfahbod 已提交
272
  return g.get_feature_tags (start_offset, feature_count, feature_tags);
273 274 275
}


B
Behdad Esfahbod 已提交
276
unsigned int
277 278 279
hb_ot_layout_script_get_language_tags (hb_face_t    *face,
				       hb_tag_t      table_tag,
				       unsigned int  script_index,
B
Behdad Esfahbod 已提交
280
				       unsigned int  start_offset,
281 282
				       unsigned int *language_count /* IN/OUT */,
				       hb_tag_t     *language_tags /* OUT */)
283
{
284
  const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
285

B
Behdad Esfahbod 已提交
286
  return s.get_lang_sys_tags (start_offset, language_count, language_tags);
287 288 289
}

hb_bool_t
290 291 292 293 294
hb_ot_layout_script_find_language (hb_face_t    *face,
				   hb_tag_t      table_tag,
				   unsigned int  script_index,
				   hb_tag_t      language_tag,
				   unsigned int *language_index)
295
{
296 297
  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX);
  const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
298

299
  if (s.find_lang_sys_index (language_tag, language_index))
300
    return true;
301 302

  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
303
  if (s.find_lang_sys_index (HB_OT_TAG_DEFAULT_LANGUAGE, language_index))
304
    return false;
305

306
  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
307
  return false;
308
}
309

310
hb_bool_t
311 312 313 314 315
hb_ot_layout_language_get_required_feature_index (hb_face_t    *face,
						  hb_tag_t      table_tag,
						  unsigned int  script_index,
						  unsigned int  language_index,
						  unsigned int *feature_index)
316
{
317
  const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
318

319
  if (feature_index) *feature_index = l.get_required_feature_index ();
320

321 322
  return l.has_required_feature ();
}
323

B
Behdad Esfahbod 已提交
324
unsigned int
325 326 327 328
hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
					   hb_tag_t      table_tag,
					   unsigned int  script_index,
					   unsigned int  language_index,
B
Behdad Esfahbod 已提交
329
					   unsigned int  start_offset,
330 331
					   unsigned int *feature_count /* IN/OUT */,
					   unsigned int *feature_indexes /* OUT */)
332
{
333 334
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
335

B
Behdad Esfahbod 已提交
336
  return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
337 338
}

B
Behdad Esfahbod 已提交
339
unsigned int
340 341 342 343
hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
					hb_tag_t      table_tag,
					unsigned int  script_index,
					unsigned int  language_index,
B
Behdad Esfahbod 已提交
344
					unsigned int  start_offset,
345 346
					unsigned int *feature_count /* IN/OUT */,
					hb_tag_t     *feature_tags /* OUT */)
347
{
348 349
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
350

351
  ASSERT_STATIC (sizeof (unsigned int) == sizeof (hb_tag_t));
B
Behdad Esfahbod 已提交
352
  unsigned int ret = l.get_feature_indexes (start_offset, feature_count, (unsigned int *) feature_tags);
353

B
Behdad Esfahbod 已提交
354 355 356 357 358
  if (feature_tags) {
    unsigned int count = *feature_count;
    for (unsigned int i = 0; i < count; i++)
      feature_tags[i] = g.get_feature_tag ((unsigned int) feature_tags[i]);
  }
359 360

  return ret;
361 362 363 364
}


hb_bool_t
365 366 367 368 369 370
hb_ot_layout_language_find_feature (hb_face_t    *face,
				    hb_tag_t      table_tag,
				    unsigned int  script_index,
				    unsigned int  language_index,
				    hb_tag_t      feature_tag,
				    unsigned int *feature_index)
371
{
372 373 374
  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX);
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
375

B
Behdad Esfahbod 已提交
376 377
  unsigned int num_features = l.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++) {
378 379 380 381
    unsigned int f_index = l.get_feature_index (i);

    if (feature_tag == g.get_feature_tag (f_index)) {
      if (feature_index) *feature_index = f_index;
382
      return true;
383 384
    }
  }
385

386
  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
387
  return false;
388
}
389

B
Behdad Esfahbod 已提交
390
unsigned int
391 392 393 394 395 396
hb_ot_layout_feature_get_lookups (hb_face_t    *face,
				  hb_tag_t      table_tag,
				  unsigned int  feature_index,
				  unsigned int  start_offset,
				  unsigned int *lookup_count /* IN/OUT */,
				  unsigned int *lookup_indexes /* OUT */)
397
{
398 399
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::Feature &f = g.get_feature (feature_index);
400

B
Behdad Esfahbod 已提交
401
  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
402 403
}

404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
static void
_hb_ot_layout_collect_lookups_lookups (hb_face_t      *face,
				       hb_tag_t        table_tag,
				       unsigned int    feature_index,
				       hb_set_t       *lookup_indexes /* OUT */)
{
  unsigned int lookup_indices[32];
  unsigned int offset, len;

  offset = 0;
  do {
    len = ARRAY_LENGTH (lookup_indices);
    hb_ot_layout_feature_get_lookups (face,
				      table_tag,
				      feature_index,
				      offset, &len,
				      lookup_indices);

    for (unsigned int i = 0; i < len; i++)
      lookup_indexes->add (lookup_indices[i]);

    offset += len;
  } while (len == ARRAY_LENGTH (lookup_indices));
}

static void
_hb_ot_layout_collect_lookups_features (hb_face_t      *face,
					hb_tag_t        table_tag,
					unsigned int    script_index,
					unsigned int    language_index,
					const hb_tag_t *features,
					hb_set_t       *lookup_indexes /* OUT */)
{
  if (!features)
  {
    /* All features */
    unsigned int count = hb_ot_layout_language_get_feature_tags (face, table_tag, script_index, language_index, 0, NULL, NULL);
    for (unsigned int feature_index = 0; feature_index < count; feature_index++)
      _hb_ot_layout_collect_lookups_lookups (face, table_tag, feature_index, lookup_indexes);
  } else {
    for (; *features; features++)
    {
      unsigned int feature_index;
      if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index, *features, &feature_index))
        _hb_ot_layout_collect_lookups_lookups (face, table_tag, feature_index, lookup_indexes);
    }
  }
}

static void
_hb_ot_layout_collect_lookups_languages (hb_face_t      *face,
					 hb_tag_t        table_tag,
					 unsigned int    script_index,
					 const hb_tag_t *languages,
					 const hb_tag_t *features,
					 hb_set_t       *lookup_indexes /* OUT */)
{
  if (!languages)
  {
    /* All languages */
    unsigned int count = hb_ot_layout_script_get_language_tags (face, table_tag, script_index, 0, NULL, NULL);
    for (unsigned int language_index = 0; language_index < count; language_index++)
      _hb_ot_layout_collect_lookups_features (face, table_tag, script_index, language_index, features, lookup_indexes);
  } else {
    for (; *languages; languages++)
    {
      unsigned int language_index;
      if (hb_ot_layout_script_find_language (face, table_tag, script_index, *languages, &language_index))
        _hb_ot_layout_collect_lookups_features (face, table_tag, script_index, language_index, features, lookup_indexes);
    }
  }
}

void
hb_ot_layout_collect_lookups (hb_face_t      *face,
			      hb_tag_t        table_tag,
			      const hb_tag_t *scripts,
			      const hb_tag_t *languages,
			      const hb_tag_t *features,
			      hb_set_t       *lookup_indexes /* OUT */)
{
  if (!scripts)
  {
    /* All scripts */
    unsigned int count = hb_ot_layout_table_get_script_tags (face, table_tag, 0, NULL, NULL);
    for (unsigned int script_index = 0; script_index < count; script_index++)
      _hb_ot_layout_collect_lookups_languages (face, table_tag, script_index, languages, features, lookup_indexes);
  } else {
    for (; *scripts; scripts++)
    {
      unsigned int script_index;
      if (hb_ot_layout_table_find_script (face, table_tag, *scripts, &script_index))
        _hb_ot_layout_collect_lookups_languages (face, table_tag, script_index, languages, features, lookup_indexes);
    }
  }
}

501 502 503 504 505 506 507 508 509 510 511
void
hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
				    hb_tag_t      table_tag,
				    unsigned int  lookup_index,
				    hb_set_t     *glyphs_before, /* OUT. May be NULL */
				    hb_set_t     *glyphs_input,  /* OUT. May be NULL */
				    hb_set_t     *glyphs_after,  /* OUT. May be NULL */
				    hb_set_t     *glyphs_output  /* OUT. May be NULL */)
{
  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return;

512
  OT::hb_collect_glyphs_context_t c (face, glyphs_before, glyphs_input, glyphs_after, glyphs_output);
513 514 515 516

  switch (table_tag) {
    case HB_OT_TAG_GSUB:
    {
517 518
      const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
      l.collect_glyphs_lookup (&c);
519 520 521 522
      return;
    }
    case HB_OT_TAG_GPOS:
    {
523 524
      const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
      l.collect_glyphs_lookup (&c);
525 526 527 528 529
      return;
    }
  }
}

B
Behdad Esfahbod 已提交
530 531

/*
532
 * OT::GSUB
B
Behdad Esfahbod 已提交
533 534 535
 */

hb_bool_t
536 537
hb_ot_layout_has_substitution (hb_face_t *face)
{
538
  return &_get_gsub (face) != &OT::Null(OT::GSUB);
539 540
}

541
hb_bool_t
542
hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
543
				      unsigned int          lookup_index,
544 545
				      const hb_codepoint_t *glyphs,
				      unsigned int          glyphs_length,
546
				      hb_bool_t             zero_context)
547
{
548
  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
549
  return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
550 551
}

B
Behdad Esfahbod 已提交
552
hb_bool_t
553
hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
554
					   unsigned int          lookup_index,
B
Behdad Esfahbod 已提交
555 556
					   const hb_codepoint_t *glyphs,
					   unsigned int          glyphs_length,
557
					   hb_bool_t             zero_context)
B
Behdad Esfahbod 已提交
558
{
559
  if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
B
Behdad Esfahbod 已提交
560 561 562 563 564
  OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, zero_context);

  const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);

  return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
B
Behdad Esfahbod 已提交
565 566
}

567
void
568
hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
569
{
570
  OT::GSUB::substitute_start (font, buffer);
571 572
}

573
hb_bool_t
574
hb_ot_layout_substitute_lookup (hb_font_t    *font,
575 576 577
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
				hb_mask_t     mask)
B
Behdad Esfahbod 已提交
578
{
579
  if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false;
B
Behdad Esfahbod 已提交
580 581 582 583 584 585

  OT::hb_apply_context_t c (font, buffer, mask);

  const OT::SubstLookup& l = hb_ot_layout_from_face (font->face)->gsub->get_lookup (lookup_index);

  return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gsub_digests[lookup_index]);
B
Behdad Esfahbod 已提交
586 587
}

588
void
589
hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
590
{
591
  OT::GSUB::substitute_finish (font, buffer);
592 593
}

B
Behdad Esfahbod 已提交
594
void
595
hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
596 597
				        unsigned int  lookup_index,
				        hb_set_t     *glyphs)
598
{
599 600 601 602 603
  OT::hb_closure_context_t c (face, glyphs);

  const OT::SubstLookup& l = _get_gsub (face).get_lookup (lookup_index);

  l.closure (&c);
604
}
605

606
/*
607
 * OT::GPOS
608 609 610
 */

hb_bool_t
611 612
hb_ot_layout_has_positioning (hb_face_t *face)
{
613
  return &_get_gpos (face) != &OT::Null(OT::GPOS);
614 615
}

616
void
617
hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
618
{
619
  OT::GPOS::position_start (font, buffer);
620 621
}

622
hb_bool_t
B
Behdad Esfahbod 已提交
623 624 625 626 627
hb_ot_layout_position_lookup (hb_font_t    *font,
			      hb_buffer_t  *buffer,
			      unsigned int  lookup_index,
			      hb_mask_t     mask)
{
628
  if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false;
B
Behdad Esfahbod 已提交
629 630 631 632 633 634

  OT::hb_apply_context_t c (font, buffer, mask);

  const OT::PosLookup& l = hb_ot_layout_from_face (font->face)->gpos->get_lookup (lookup_index);

  return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
B
Behdad Esfahbod 已提交
635 636
}

637
void
638
hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attached_marks)
639
{
640
  OT::GPOS::position_finish (font, buffer, zero_width_attached_marks);
641
}