hb-ot-layout.cc 22.6 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 64
  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));

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

72
  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
B
Behdad Esfahbod 已提交
73 74
  {
    layout->gsub_digests[i].init ();
B
Behdad Esfahbod 已提交
75
    layout->gsub->get_lookup (i).add_coverage (&layout->gsub_digests[i]);
B
Behdad Esfahbod 已提交
76
  }
77
  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
B
Behdad Esfahbod 已提交
78 79
  {
    layout->gpos_digests[i].init ();
B
Behdad Esfahbod 已提交
80
    layout->gpos->get_lookup (i).add_coverage (&layout->gpos_digests[i]);
B
Behdad Esfahbod 已提交
81
  }
82

B
Behdad Esfahbod 已提交
83
  return layout;
B
Behdad Esfahbod 已提交
84 85
}

86
void
87
_hb_ot_layout_destroy (hb_ot_layout_t *layout)
B
Behdad Esfahbod 已提交
88
{
B
Behdad Esfahbod 已提交
89 90 91
  hb_blob_destroy (layout->gdef_blob);
  hb_blob_destroy (layout->gsub_blob);
  hb_blob_destroy (layout->gpos_blob);
B
Behdad Esfahbod 已提交
92

93 94 95
  free (layout->gsub_digests);
  free (layout->gpos_digests);

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

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

118

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

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

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

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

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

165

166 167 168 169
/*
 * GSUB/GPOS
 */

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


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

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

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

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

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

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

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

B
Minor  
Behdad Esfahbod 已提交
217 218 219 220 221
  /* 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 已提交
222
  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
223
  return false;
B
Behdad Esfahbod 已提交
224 225 226 227 228 229
}

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

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

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

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

260 261 262 263 264
  /* 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;
265
    return false;
266 267
  }

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

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

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


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

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

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

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

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

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

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

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

332 333
  return l.has_required_feature ();
}
334

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

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

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

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

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

  return ret;
372 373 374 375
}


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

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

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

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

B
Behdad Esfahbod 已提交
412
  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
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
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 */)
{
448 449 450 451 452 453
  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 已提交
454 455 456 457
    _hb_ot_layout_collect_lookups_lookups (face,
					   table_tag,
					   required_feature_index,
					   lookup_indexes);
458

459 460 461
  if (!features)
  {
    /* All features */
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485
    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
  {
486 487 488
    for (; *features; features++)
    {
      unsigned int feature_index;
B
Behdad Esfahbod 已提交
489 490 491 492 493 494 495 496 497 498
      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);
499 500 501 502 503 504 505 506 507 508 509 510
    }
  }
}

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

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

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

594 595 596 597 598 599 600 601 602 603 604
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 已提交
605 606 607 608 609
  OT::hb_collect_glyphs_context_t c (face,
				     glyphs_before,
				     glyphs_input,
				     glyphs_after,
				     glyphs_output);
610

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

B
Behdad Esfahbod 已提交
628 629

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

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

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

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

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

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

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

  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 已提交
685 686
}

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

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

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

  l.closure (&c);
703
}
704

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

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

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

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

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

  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 已提交
735 736
}

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

hb_bool_t
744 745 746 747 748 749
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 */)
750 751
{
  const OT::GPOS &gpos = _get_gpos (face);
752
  const hb_tag_t tag = HB_TAG ('s','i','z','e');
753

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

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

	return true;
      }
774 775 776
    }
  }

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

785
  return false;
786
}