hb-ot-layout.cc 22.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
#include "hb-ot-layout-gdef-table.hh"
#include "hb-ot-layout-gsub-table.hh"
#include "hb-ot-layout-gpos-table.hh"
B
Behdad Esfahbod 已提交
36 37

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

B
Behdad Esfahbod 已提交
40

41
HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
42

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

50 51
  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 已提交
52

53 54
  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 已提交
55

56 57
  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 已提交
58

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

62 63
  layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
  layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
64

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

72
  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
73
    layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
74
  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
75
    layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
76

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

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

87 88 89 90 91 92 93
  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
    layout->gsub_accels[i].fini (layout->gsub->get_lookup (i));
  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
    layout->gpos_accels[i].fini (layout->gpos->get_lookup (i));

  free (layout->gsub_accels);
  free (layout->gpos_accels);
94

B
Behdad Esfahbod 已提交
95
  free (layout);
96
}
B
Behdad Esfahbod 已提交
97

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

117

B
Behdad Esfahbod 已提交
118 119 120 121 122
/*
 * GDEF
 */

hb_bool_t
123
hb_ot_layout_has_glyph_classes (hb_face_t *face)
B
Behdad Esfahbod 已提交
124
{
125
  return _get_gdef (face).has_glyph_classes ();
B
Behdad Esfahbod 已提交
126 127
}

128 129 130 131 132 133
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 已提交
134

135 136 137 138 139 140 141 142
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 已提交
143
unsigned int
144
hb_ot_layout_get_attach_points (hb_face_t      *face,
B
Behdad Esfahbod 已提交
145
				hb_codepoint_t  glyph,
B
Behdad Esfahbod 已提交
146
				unsigned int    start_offset,
B
Behdad Esfahbod 已提交
147 148 149
				unsigned int   *point_count /* IN/OUT */,
				unsigned int   *point_array /* OUT */)
{
B
Behdad Esfahbod 已提交
150
  return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
B
Behdad Esfahbod 已提交
151 152
}

B
Behdad Esfahbod 已提交
153
unsigned int
154 155 156 157 158 159
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 已提交
160
{
161
  return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
B
Behdad Esfahbod 已提交
162 163
}

164

165 166 167 168
/*
 * GSUB/GPOS
 */

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


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

B
Behdad Esfahbod 已提交
190
  return g.get_script_tags (start_offset, script_count, script_tags);
191 192
}

B
Minor  
Behdad Esfahbod 已提交
193 194
#define HB_OT_TAG_LATIN_SCRIPT		HB_TAG ('l', 'a', 't', 'n')

195
hb_bool_t
196 197 198 199
hb_ot_layout_table_find_script (hb_face_t    *face,
				hb_tag_t      table_tag,
				hb_tag_t      script_tag,
				unsigned int *script_index)
200
{
201 202
  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
203 204

  if (g.find_script_index (script_tag, script_index))
205
    return true;
206 207

  /* try finding 'DFLT' */
208
  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
209
    return false;
210

211 212
  /* try with 'dflt'; MS site has had typos and many fonts use it now :(.
   * including many versions of DejaVu Sans Mono! */
213
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index))
214
    return false;
B
Behdad Esfahbod 已提交
215

B
Minor  
Behdad Esfahbod 已提交
216 217 218 219 220
  /* try with 'latn'; some old fonts put their features there even though
     they're really trying to support Thai, for example :( */
  if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index))
    return false;

B
Behdad Esfahbod 已提交
221
  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
222
  return false;
B
Behdad Esfahbod 已提交
223 224 225 226 227 228
}

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 已提交
229 230
				  unsigned int   *script_index,
				  hb_tag_t       *chosen_script)
B
Behdad Esfahbod 已提交
231
{
232 233
  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 已提交
234 235 236

  while (*script_tags)
  {
B
Behdad Esfahbod 已提交
237 238 239
    if (g.find_script_index (*script_tags, script_index)) {
      if (chosen_script)
        *chosen_script = *script_tags;
240
      return true;
B
Behdad Esfahbod 已提交
241
    }
B
Behdad Esfahbod 已提交
242 243 244 245
    script_tags++;
  }

  /* try finding 'DFLT' */
B
Behdad Esfahbod 已提交
246 247 248
  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
249
    return false;
B
Behdad Esfahbod 已提交
250
  }
B
Behdad Esfahbod 已提交
251 252

  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
B
Behdad Esfahbod 已提交
253 254 255
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
256
    return false;
B
Behdad Esfahbod 已提交
257
  }
258

259 260 261 262 263
  /* try with 'latn'; some old fonts put their features there even though
     they're really trying to support Thai, for example :( */
  if (g.find_script_index (HB_OT_TAG_LATIN_SCRIPT, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_LATIN_SCRIPT;
264
    return false;
265 266
  }

267
  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
B
Behdad Esfahbod 已提交
268 269
  if (chosen_script)
    *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
270
  return false;
271 272
}

B
Behdad Esfahbod 已提交
273
unsigned int
274 275
hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
				     hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
276
				     unsigned int  start_offset,
277 278
				     unsigned int *feature_count /* IN/OUT */,
				     hb_tag_t     *feature_tags /* OUT */)
279
{
280
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
281

B
Behdad Esfahbod 已提交
282
  return g.get_feature_tags (start_offset, feature_count, feature_tags);
283 284 285
}


B
Behdad Esfahbod 已提交
286
unsigned int
287 288 289
hb_ot_layout_script_get_language_tags (hb_face_t    *face,
				       hb_tag_t      table_tag,
				       unsigned int  script_index,
B
Behdad Esfahbod 已提交
290
				       unsigned int  start_offset,
291 292
				       unsigned int *language_count /* IN/OUT */,
				       hb_tag_t     *language_tags /* OUT */)
293
{
294
  const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
295

B
Behdad Esfahbod 已提交
296
  return s.get_lang_sys_tags (start_offset, language_count, language_tags);
297 298 299
}

hb_bool_t
300 301 302 303 304
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)
305
{
306 307
  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);
308

309
  if (s.find_lang_sys_index (language_tag, language_index))
310
    return true;
311 312

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

316
  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
317
  return false;
318
}
319

320
hb_bool_t
321 322 323 324 325
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)
326
{
327
  const OT::LangSys &l = get_gsubgpos_table (face, table_tag).get_script (script_index).get_lang_sys (language_index);
328

329
  if (feature_index) *feature_index = l.get_required_feature_index ();
330

331 332
  return l.has_required_feature ();
}
333

B
Behdad Esfahbod 已提交
334
unsigned int
335 336 337 338
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 已提交
339
					   unsigned int  start_offset,
340 341
					   unsigned int *feature_count /* IN/OUT */,
					   unsigned int *feature_indexes /* OUT */)
342
{
343 344
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
345

B
Behdad Esfahbod 已提交
346
  return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
347 348
}

B
Behdad Esfahbod 已提交
349
unsigned int
350 351 352 353
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 已提交
354
					unsigned int  start_offset,
355 356
					unsigned int *feature_count /* IN/OUT */,
					hb_tag_t     *feature_tags /* OUT */)
357
{
358 359
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
360

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

B
Behdad Esfahbod 已提交
364 365 366 367 368
  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]);
  }
369 370

  return ret;
371 372 373 374
}


hb_bool_t
375 376 377 378 379 380
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)
381
{
382 383 384
  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);
385

B
Behdad Esfahbod 已提交
386 387
  unsigned int num_features = l.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++) {
388 389 390 391
    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;
392
      return true;
393 394
    }
  }
395

396
  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
397
  return false;
398
}
399

B
Behdad Esfahbod 已提交
400
unsigned int
401 402 403 404 405 406
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 */)
407
{
408 409
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::Feature &f = g.get_feature (feature_index);
410

B
Behdad Esfahbod 已提交
411
  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
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
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 */)
{
447 448 449 450 451 452
  unsigned int required_feature_index;
  if (hb_ot_layout_language_get_required_feature_index (face,
							table_tag,
							script_index,
							language_index,
							&required_feature_index))
B
Behdad Esfahbod 已提交
453 454 455 456
    _hb_ot_layout_collect_lookups_lookups (face,
					   table_tag,
					   required_feature_index,
					   lookup_indexes);
457

458 459 460
  if (!features)
  {
    /* All features */
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
    unsigned int feature_indices[32];
    unsigned int offset, len;

    offset = 0;
    do {
      len = ARRAY_LENGTH (feature_indices);
      hb_ot_layout_language_get_feature_indexes (face,
						 table_tag,
						 script_index,
						 language_index,
						 offset, &len,
						 feature_indices);

      for (unsigned int i = 0; i < len; i++)
	_hb_ot_layout_collect_lookups_lookups (face,
					       table_tag,
					       feature_indices[i],
					       lookup_indexes);

      offset += len;
    } while (len == ARRAY_LENGTH (feature_indices));
  }
  else
  {
485 486 487
    for (; *features; features++)
    {
      unsigned int feature_index;
B
Behdad Esfahbod 已提交
488 489 490 491 492 493 494 495 496 497
      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);
498 499 500 501 502 503 504 505 506 507 508 509
    }
  }
}

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 */)
{
510 511 512 513 514 515 516
  _hb_ot_layout_collect_lookups_features (face,
					  table_tag,
					  script_index,
					  HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
					  features,
					  lookup_indexes);

517 518 519
  if (!languages)
  {
    /* All languages */
B
Behdad Esfahbod 已提交
520 521 522 523
    unsigned int count = hb_ot_layout_script_get_language_tags (face,
								table_tag,
								script_index,
								0, NULL, NULL);
524
    for (unsigned int language_index = 0; language_index < count; language_index++)
B
Behdad Esfahbod 已提交
525 526 527 528 529 530
      _hb_ot_layout_collect_lookups_features (face,
					      table_tag,
					      script_index,
					      language_index,
					      features,
					      lookup_indexes);
531 532 533
  }
  else
  {
534 535 536
    for (; *languages; languages++)
    {
      unsigned int language_index;
B
Behdad Esfahbod 已提交
537 538 539 540 541 542 543 544 545 546 547
      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);
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
    }
  }
}

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 */
B
Behdad Esfahbod 已提交
563 564 565
    unsigned int count = hb_ot_layout_table_get_script_tags (face,
							     table_tag,
							     0, NULL, NULL);
566
    for (unsigned int script_index = 0; script_index < count; script_index++)
B
Behdad Esfahbod 已提交
567 568 569 570 571 572
      _hb_ot_layout_collect_lookups_languages (face,
					       table_tag,
					       script_index,
					       languages,
					       features,
					       lookup_indexes);
573 574 575
  }
  else
  {
576 577 578
    for (; *scripts; scripts++)
    {
      unsigned int script_index;
B
Behdad Esfahbod 已提交
579 580 581 582 583 584 585 586 587 588
      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);
589 590 591 592
    }
  }
}

593 594 595 596 597 598 599 600 601 602 603
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;

B
Behdad Esfahbod 已提交
604 605 606 607 608
  OT::hb_collect_glyphs_context_t c (face,
				     glyphs_before,
				     glyphs_input,
				     glyphs_after,
				     glyphs_output);
609

610 611
  switch (table_tag)
  {
612 613
    case HB_OT_TAG_GSUB:
    {
614 615
      const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
      l.collect_glyphs_lookup (&c);
616 617 618 619
      return;
    }
    case HB_OT_TAG_GPOS:
    {
620 621
      const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
      l.collect_glyphs_lookup (&c);
622 623 624 625 626
      return;
    }
  }
}

B
Behdad Esfahbod 已提交
627 628

/*
629
 * OT::GSUB
B
Behdad Esfahbod 已提交
630 631 632
 */

hb_bool_t
633 634
hb_ot_layout_has_substitution (hb_face_t *face)
{
635
  return &_get_gsub (face) != &OT::Null(OT::GSUB);
636 637
}

638
hb_bool_t
639
hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
640
				      unsigned int          lookup_index,
641 642
				      const hb_codepoint_t *glyphs,
				      unsigned int          glyphs_length,
643
				      hb_bool_t             zero_context)
644
{
645
  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
646
  return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
647 648
}

B
Behdad Esfahbod 已提交
649
hb_bool_t
650
hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
651
					   unsigned int          lookup_index,
B
Behdad Esfahbod 已提交
652 653
					   const hb_codepoint_t *glyphs,
					   unsigned int          glyphs_length,
654
					   hb_bool_t             zero_context)
B
Behdad Esfahbod 已提交
655
{
656
  if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
B
Behdad Esfahbod 已提交
657 658 659 660
  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);

661
  return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest);
B
Behdad Esfahbod 已提交
662 663
}

664
void
665
hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
666
{
667
  OT::GSUB::substitute_start (font, buffer);
668 669
}

670
hb_bool_t
671
hb_ot_layout_substitute_lookup (hb_font_t    *font,
672 673
				hb_buffer_t  *buffer,
				unsigned int  lookup_index,
674
				hb_mask_t     mask,
675
				hb_bool_t     auto_zwj)
B
Behdad Esfahbod 已提交
676
{
677
  if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gsub_lookup_count)) return false;
B
Behdad Esfahbod 已提交
678

679
  OT::hb_apply_context_t c (0, font, buffer, mask, auto_zwj);
B
Behdad Esfahbod 已提交
680 681 682

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

683
  return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gsub_accels[lookup_index].digest);
B
Behdad Esfahbod 已提交
684 685
}

686
void
687
hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
688
{
689
  OT::GSUB::substitute_finish (font, buffer);
690 691
}

B
Behdad Esfahbod 已提交
692
void
693
hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
694 695
				        unsigned int  lookup_index,
				        hb_set_t     *glyphs)
696
{
697 698 699 700 701
  OT::hb_closure_context_t c (face, glyphs);

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

  l.closure (&c);
702
}
703

704
/*
705
 * OT::GPOS
706 707 708
 */

hb_bool_t
709 710
hb_ot_layout_has_positioning (hb_face_t *face)
{
711
  return &_get_gpos (face) != &OT::Null(OT::GPOS);
712 713
}

714
void
715
hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
716
{
717
  OT::GPOS::position_start (font, buffer);
718 719
}

720
hb_bool_t
B
Behdad Esfahbod 已提交
721 722 723
hb_ot_layout_position_lookup (hb_font_t    *font,
			      hb_buffer_t  *buffer,
			      unsigned int  lookup_index,
724
			      hb_mask_t     mask,
725
			      hb_bool_t     auto_zwj)
B
Behdad Esfahbod 已提交
726
{
727
  if (unlikely (lookup_index >= hb_ot_layout_from_face (font->face)->gpos_lookup_count)) return false;
B
Behdad Esfahbod 已提交
728

729
  OT::hb_apply_context_t c (1, font, buffer, mask, auto_zwj);
B
Behdad Esfahbod 已提交
730 731 732

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

733
  return l.apply_string (&c, &hb_ot_layout_from_face (font->face)->gpos_accels[lookup_index].digest);
B
Behdad Esfahbod 已提交
734 735
}

736
void
737
hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
738
{
739
  OT::GPOS::position_finish (font, buffer);
740
}
741 742

hb_bool_t
743 744 745 746 747 748
hb_ot_layout_get_size_params (hb_face_t    *face,
			      unsigned int *design_size,       /* OUT.  May be NULL */
			      unsigned int *subfamily_id,      /* OUT.  May be NULL */
			      unsigned int *subfamily_name_id, /* OUT.  May be NULL */
			      unsigned int *range_start,       /* OUT.  May be NULL */
			      unsigned int *range_end          /* OUT.  May be NULL */)
749 750
{
  const OT::GPOS &gpos = _get_gpos (face);
751
  const hb_tag_t tag = HB_TAG ('s','i','z','e');
752

753 754 755
  unsigned int num_features = gpos.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++)
  {
756
    if (tag == gpos.get_feature_tag (i))
757
    {
758
      const OT::Feature &f = gpos.get_feature (i);
759
      const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
760

761
      if (params.designSize)
762
      {
763
#define PARAM(a, A) if (a) *a = params.A
764 765 766 767 768 769
	PARAM (design_size, designSize);
	PARAM (subfamily_id, subfamilyID);
	PARAM (subfamily_name_id, subfamilyNameID);
	PARAM (range_start, rangeStart);
	PARAM (range_end, rangeEnd);
#undef PARAM
770 771 772

	return true;
      }
773 774 775
    }
  }

776
#define PARAM(a, A) if (a) *a = 0
777 778 779 780 781
  PARAM (design_size, designSize);
  PARAM (subfamily_id, subfamilyID);
  PARAM (subfamily_name_id, subfamilyNameID);
  PARAM (range_start, rangeStart);
  PARAM (range_end, rangeEnd);
782
#undef PARAM
783

784
  return false;
785
}