hb-ot-layout.cc 28.2 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.
5
 * Copyright © 2012,2013  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"
36
#include "hb-ot-layout-jstf-table.hh"
B
Behdad Esfahbod 已提交
37

B
Behdad Esfahbod 已提交
38 39
#include "hb-ot-map-private.hh"

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

B
Behdad Esfahbod 已提交
43

44
HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
45

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

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

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

59 60
  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 已提交
61

62 63 64
  layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
  layout->gpos_lookup_count = layout->gpos->get_lookup_count ();

65 66
  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));
67

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

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

B
Behdad Esfahbod 已提交
80
  return layout;
B
Behdad Esfahbod 已提交
81 82
}

83
void
84
_hb_ot_layout_destroy (hb_ot_layout_t *layout)
B
Behdad Esfahbod 已提交
85
{
86
  for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
87
    layout->gsub_accels[i].fini ();
88
  for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
89
    layout->gpos_accels[i].fini ();
90 91 92

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

B
Bradley Grainger 已提交
94 95 96 97
  hb_blob_destroy (layout->gdef_blob);
  hb_blob_destroy (layout->gsub_blob);
  hb_blob_destroy (layout->gpos_blob);

B
Behdad Esfahbod 已提交
98
  free (layout);
99
}
B
Behdad Esfahbod 已提交
100

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

120

B
Behdad Esfahbod 已提交
121 122 123 124 125
/*
 * GDEF
 */

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

S
Sascha Brawer 已提交
131 132 133
/**
 * Since: 0.9.7
 **/
134 135 136 137 138 139
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 已提交
140

S
Sascha Brawer 已提交
141 142 143
/**
 * Since: 0.9.7
 **/
144 145 146 147 148 149 150 151
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 已提交
152
unsigned int
153
hb_ot_layout_get_attach_points (hb_face_t      *face,
B
Behdad Esfahbod 已提交
154
				hb_codepoint_t  glyph,
B
Behdad Esfahbod 已提交
155
				unsigned int    start_offset,
B
Behdad Esfahbod 已提交
156 157 158
				unsigned int   *point_count /* IN/OUT */,
				unsigned int   *point_array /* OUT */)
{
B
Behdad Esfahbod 已提交
159
  return _get_gdef (face).get_attach_points (glyph, start_offset, point_count, point_array);
B
Behdad Esfahbod 已提交
160 161
}

B
Behdad Esfahbod 已提交
162
unsigned int
163 164 165 166 167 168
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 已提交
169
{
170
  return _get_gdef (font->face).get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array);
B
Behdad Esfahbod 已提交
171 172
}

173

174 175 176 177
/*
 * GSUB/GPOS
 */

178
static const OT::GSUBGPOS&
179 180
get_gsubgpos_table (hb_face_t *face,
		    hb_tag_t   table_tag)
181
{
182
  switch (table_tag) {
183 184
    case HB_OT_TAG_GSUB: return _get_gsub (face);
    case HB_OT_TAG_GPOS: return _get_gpos (face);
185
    default:             return OT::Null(OT::GSUBGPOS);
186 187 188 189
  }
}


B
Behdad Esfahbod 已提交
190
unsigned int
191 192
hb_ot_layout_table_get_script_tags (hb_face_t    *face,
				    hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
193
				    unsigned int  start_offset,
194 195
				    unsigned int *script_count /* IN/OUT */,
				    hb_tag_t     *script_tags /* OUT */)
196
{
197
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
198

B
Behdad Esfahbod 已提交
199
  return g.get_script_tags (start_offset, script_count, script_tags);
200 201
}

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

204
hb_bool_t
205 206 207 208
hb_ot_layout_table_find_script (hb_face_t    *face,
				hb_tag_t      table_tag,
				hb_tag_t      script_tag,
				unsigned int *script_index)
209
{
210 211
  ASSERT_STATIC (OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX);
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
212 213

  if (g.find_script_index (script_tag, script_index))
214
    return true;
215 216

  /* try finding 'DFLT' */
217
  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index))
218
    return false;
219

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

B
Minor  
Behdad Esfahbod 已提交
225 226 227 228 229
  /* 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 已提交
230
  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
231
  return false;
B
Behdad Esfahbod 已提交
232 233 234 235 236 237
}

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 已提交
238 239
				  unsigned int   *script_index,
				  hb_tag_t       *chosen_script)
B
Behdad Esfahbod 已提交
240
{
241 242
  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 已提交
243 244 245

  while (*script_tags)
  {
B
Behdad Esfahbod 已提交
246 247 248
    if (g.find_script_index (*script_tags, script_index)) {
      if (chosen_script)
        *chosen_script = *script_tags;
249
      return true;
B
Behdad Esfahbod 已提交
250
    }
B
Behdad Esfahbod 已提交
251 252 253 254
    script_tags++;
  }

  /* try finding 'DFLT' */
B
Behdad Esfahbod 已提交
255 256 257
  if (g.find_script_index (HB_OT_TAG_DEFAULT_SCRIPT, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_DEFAULT_SCRIPT;
258
    return false;
B
Behdad Esfahbod 已提交
259
  }
B
Behdad Esfahbod 已提交
260 261

  /* try with 'dflt'; MS site has had typos and many fonts use it now :( */
B
Behdad Esfahbod 已提交
262 263 264
  if (g.find_script_index (HB_OT_TAG_DEFAULT_LANGUAGE, script_index)) {
    if (chosen_script)
      *chosen_script = HB_OT_TAG_DEFAULT_LANGUAGE;
265
    return false;
B
Behdad Esfahbod 已提交
266
  }
267

268 269 270 271 272
  /* 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;
273
    return false;
274 275
  }

276
  if (script_index) *script_index = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
B
Behdad Esfahbod 已提交
277 278
  if (chosen_script)
    *chosen_script = HB_OT_LAYOUT_NO_SCRIPT_INDEX;
279
  return false;
280 281
}

B
Behdad Esfahbod 已提交
282
unsigned int
283 284
hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
				     hb_tag_t      table_tag,
B
Behdad Esfahbod 已提交
285
				     unsigned int  start_offset,
286 287
				     unsigned int *feature_count /* IN/OUT */,
				     hb_tag_t     *feature_tags /* OUT */)
288
{
289
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
290

B
Behdad Esfahbod 已提交
291
  return g.get_feature_tags (start_offset, feature_count, feature_tags);
292 293 294
}


B
Behdad Esfahbod 已提交
295
unsigned int
296 297 298
hb_ot_layout_script_get_language_tags (hb_face_t    *face,
				       hb_tag_t      table_tag,
				       unsigned int  script_index,
B
Behdad Esfahbod 已提交
299
				       unsigned int  start_offset,
300 301
				       unsigned int *language_count /* IN/OUT */,
				       hb_tag_t     *language_tags /* OUT */)
302
{
303
  const OT::Script &s = get_gsubgpos_table (face, table_tag).get_script (script_index);
304

B
Behdad Esfahbod 已提交
305
  return s.get_lang_sys_tags (start_offset, language_count, language_tags);
306 307 308
}

hb_bool_t
309 310 311 312 313
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)
314
{
315 316
  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);
317

318
  if (s.find_lang_sys_index (language_tag, language_index))
319
    return true;
320 321

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

325
  if (language_index) *language_index = HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX;
326
  return false;
327
}
328

B
Behdad Esfahbod 已提交
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
hb_bool_t
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)
{
  return hb_ot_layout_language_get_required_feature (face,
						     table_tag,
						     script_index,
						     language_index,
						     feature_index,
						     NULL);
}

S
Sascha Brawer 已提交
344 345 346
/**
 * Since: 0.9.30
 **/
347
hb_bool_t
348 349 350 351 352 353
hb_ot_layout_language_get_required_feature (hb_face_t    *face,
					    hb_tag_t      table_tag,
					    unsigned int  script_index,
					    unsigned int  language_index,
					    unsigned int *feature_index,
					    hb_tag_t     *feature_tag)
354
{
355 356
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
357

358 359 360
  unsigned int index = l.get_required_feature_index ();
  if (feature_index) *feature_index = index;
  if (feature_tag) *feature_tag = g.get_feature_tag (index);
361

362 363
  return l.has_required_feature ();
}
364

B
Behdad Esfahbod 已提交
365
unsigned int
366 367 368 369
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 已提交
370
					   unsigned int  start_offset,
371 372
					   unsigned int *feature_count /* IN/OUT */,
					   unsigned int *feature_indexes /* OUT */)
373
{
374 375
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
376

B
Behdad Esfahbod 已提交
377
  return l.get_feature_indexes (start_offset, feature_count, feature_indexes);
378 379
}

B
Behdad Esfahbod 已提交
380
unsigned int
381 382 383 384
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 已提交
385
					unsigned int  start_offset,
386 387
					unsigned int *feature_count /* IN/OUT */,
					hb_tag_t     *feature_tags /* OUT */)
388
{
389 390
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
391

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

B
Behdad Esfahbod 已提交
395 396 397 398 399
  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]);
  }
400 401

  return ret;
402 403 404 405
}


hb_bool_t
406 407 408 409 410 411
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)
412
{
413 414 415
  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);
416

B
Behdad Esfahbod 已提交
417 418
  unsigned int num_features = l.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++) {
419 420 421 422
    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;
423
      return true;
424 425
    }
  }
426

427
  if (feature_index) *feature_index = HB_OT_LAYOUT_NO_FEATURE_INDEX;
428
  return false;
429
}
430

S
Sascha Brawer 已提交
431 432 433
/**
 * Since: 0.9.7
 **/
B
Behdad Esfahbod 已提交
434
unsigned int
435 436 437 438 439 440
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 */)
441
{
442 443
  const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
  const OT::Feature &f = g.get_feature (feature_index);
444

B
Behdad Esfahbod 已提交
445
  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
446 447
}

S
Sascha Brawer 已提交
448 449 450
/**
 * Since: 0.9.22
 **/
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
unsigned int
hb_ot_layout_table_get_lookup_count (hb_face_t    *face,
				     hb_tag_t      table_tag)
{
  switch (table_tag)
  {
    case HB_OT_TAG_GSUB:
    {
      return hb_ot_layout_from_face (face)->gsub_lookup_count;
    }
    case HB_OT_TAG_GPOS:
    {
      return hb_ot_layout_from_face (face)->gpos_lookup_count;
    }
  }
B
Behdad Esfahbod 已提交
466
  return 0;
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 501 502 503
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)
  {
504
    unsigned int required_feature_index;
505 506 507 508 509 510
    if (hb_ot_layout_language_get_required_feature (face,
						    table_tag,
						    script_index,
						    language_index,
						    &required_feature_index,
						    NULL))
511 512 513 514 515
      _hb_ot_layout_collect_lookups_lookups (face,
					     table_tag,
					     required_feature_index,
					     lookup_indexes);

516
    /* All features */
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
    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
  {
541 542 543
    for (; *features; features++)
    {
      unsigned int feature_index;
B
Behdad Esfahbod 已提交
544 545 546 547 548 549 550 551 552 553
      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);
554 555 556 557 558 559 560 561 562 563 564 565
    }
  }
}

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 */)
{
566 567 568 569 570 571 572
  _hb_ot_layout_collect_lookups_features (face,
					  table_tag,
					  script_index,
					  HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
					  features,
					  lookup_indexes);

573 574 575
  if (!languages)
  {
    /* All languages */
B
Behdad Esfahbod 已提交
576 577 578 579
    unsigned int count = hb_ot_layout_script_get_language_tags (face,
								table_tag,
								script_index,
								0, NULL, NULL);
580
    for (unsigned int language_index = 0; language_index < count; language_index++)
B
Behdad Esfahbod 已提交
581 582 583 584 585 586
      _hb_ot_layout_collect_lookups_features (face,
					      table_tag,
					      script_index,
					      language_index,
					      features,
					      lookup_indexes);
587 588 589
  }
  else
  {
590 591 592
    for (; *languages; languages++)
    {
      unsigned int language_index;
B
Behdad Esfahbod 已提交
593 594 595 596 597 598 599 600 601 602 603
      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);
604 605 606 607
    }
  }
}

S
Sascha Brawer 已提交
608 609 610
/**
 * Since: 0.9.8
 **/
611 612 613 614 615 616 617 618 619 620 621
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 已提交
622 623 624
    unsigned int count = hb_ot_layout_table_get_script_tags (face,
							     table_tag,
							     0, NULL, NULL);
625
    for (unsigned int script_index = 0; script_index < count; script_index++)
B
Behdad Esfahbod 已提交
626 627 628 629 630 631
      _hb_ot_layout_collect_lookups_languages (face,
					       table_tag,
					       script_index,
					       languages,
					       features,
					       lookup_indexes);
632 633 634
  }
  else
  {
635 636 637
    for (; *scripts; scripts++)
    {
      unsigned int script_index;
B
Behdad Esfahbod 已提交
638 639 640 641 642 643 644 645 646 647
      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);
648 649 650 651
    }
  }
}

S
Sascha Brawer 已提交
652 653 654
/**
 * Since: 0.9.7
 **/
655 656 657 658 659 660 661 662 663 664 665
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 已提交
666 667 668 669 670
  OT::hb_collect_glyphs_context_t c (face,
				     glyphs_before,
				     glyphs_input,
				     glyphs_after,
				     glyphs_output);
671

672 673
  switch (table_tag)
  {
674 675
    case HB_OT_TAG_GSUB:
    {
676
      const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
B
Behdad Esfahbod 已提交
677
      l.collect_glyphs (&c);
678 679 680 681
      return;
    }
    case HB_OT_TAG_GPOS:
    {
682
      const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
B
Behdad Esfahbod 已提交
683
      l.collect_glyphs (&c);
684 685 686 687 688
      return;
    }
  }
}

B
Behdad Esfahbod 已提交
689 690

/*
691
 * OT::GSUB
B
Behdad Esfahbod 已提交
692 693 694
 */

hb_bool_t
695 696
hb_ot_layout_has_substitution (hb_face_t *face)
{
697
  return &_get_gsub (face) != &OT::Null(OT::GSUB);
698 699
}

S
Sascha Brawer 已提交
700 701 702
/**
 * Since: 0.9.7
 **/
703
hb_bool_t
704
hb_ot_layout_lookup_would_substitute (hb_face_t            *face,
705
				      unsigned int          lookup_index,
706 707
				      const hb_codepoint_t *glyphs,
				      unsigned int          glyphs_length,
708
				      hb_bool_t             zero_context)
709
{
710
  if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return false;
711
  return hb_ot_layout_lookup_would_substitute_fast (face, lookup_index, glyphs, glyphs_length, zero_context);
712 713
}

B
Behdad Esfahbod 已提交
714
hb_bool_t
715
hb_ot_layout_lookup_would_substitute_fast (hb_face_t            *face,
716
					   unsigned int          lookup_index,
B
Behdad Esfahbod 已提交
717 718
					   const hb_codepoint_t *glyphs,
					   unsigned int          glyphs_length,
719
					   hb_bool_t             zero_context)
B
Behdad Esfahbod 已提交
720
{
721
  if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
B
Behdad Esfahbod 已提交
722 723 724 725
  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);

726
  return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
B
Behdad Esfahbod 已提交
727 728
}

729
void
730
hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer)
731
{
732
  OT::GSUB::substitute_start (font, buffer);
733 734 735
}

void
736
hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
737
{
738
  OT::GSUB::substitute_finish (font, buffer);
739 740
}

S
Sascha Brawer 已提交
741 742 743
/**
 * Since: 0.9.7
 **/
B
Behdad Esfahbod 已提交
744
void
745
hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
746 747
				        unsigned int  lookup_index,
				        hb_set_t     *glyphs)
748
{
749 750 751 752 753
  OT::hb_closure_context_t c (face, glyphs);

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

  l.closure (&c);
754
}
755

756
/*
757
 * OT::GPOS
758 759 760
 */

hb_bool_t
761 762
hb_ot_layout_has_positioning (hb_face_t *face)
{
763
  return &_get_gpos (face) != &OT::Null(OT::GPOS);
764 765
}

766
void
767
hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
768
{
769
  OT::GPOS::position_start (font, buffer);
770 771
}

772
void
773
hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
774
{
775
  OT::GPOS::position_finish (font, buffer);
776
}
777

S
Sascha Brawer 已提交
778 779 780
/**
 * Since: 0.9.8
 **/
781
hb_bool_t
782 783 784 785 786 787
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 */)
788 789
{
  const OT::GPOS &gpos = _get_gpos (face);
790
  const hb_tag_t tag = HB_TAG ('s','i','z','e');
791

792 793 794
  unsigned int num_features = gpos.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++)
  {
795
    if (tag == gpos.get_feature_tag (i))
796
    {
797
      const OT::Feature &f = gpos.get_feature (i);
798
      const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
799

800
      if (params.designSize)
801
      {
802
#define PARAM(a, A) if (a) *a = params.A
803 804 805 806 807 808
	PARAM (design_size, designSize);
	PARAM (subfamily_id, subfamilyID);
	PARAM (subfamily_name_id, subfamilyNameID);
	PARAM (range_start, rangeStart);
	PARAM (range_end, rangeEnd);
#undef PARAM
809 810 811

	return true;
      }
812 813 814
    }
  }

815
#define PARAM(a, A) if (a) *a = 0
816 817 818 819 820
  PARAM (design_size, designSize);
  PARAM (subfamily_id, subfamilyID);
  PARAM (subfamily_name_id, subfamilyNameID);
  PARAM (range_start, rangeStart);
  PARAM (range_end, rangeEnd);
821
#undef PARAM
822

823
  return false;
824
}
B
Behdad Esfahbod 已提交
825 826 827


/*
B
Behdad Esfahbod 已提交
828
 * Parts of different types are implemented here such that they have direct
B
Behdad Esfahbod 已提交
829 830 831 832
 * access to GSUB/GPOS lookups.
 */


B
Behdad Esfahbod 已提交
833 834 835
struct GSUBProxy
{
  static const unsigned int table_index = 0;
B
Behdad Esfahbod 已提交
836
  static const bool inplace = false;
B
Behdad Esfahbod 已提交
837 838 839 840 841 842 843 844 845 846 847 848 849
  typedef OT::SubstLookup Lookup;

  GSUBProxy (hb_face_t *face) :
    table (*hb_ot_layout_from_face (face)->gsub),
    accels (hb_ot_layout_from_face (face)->gsub_accels) {}

  const OT::GSUB &table;
  const hb_ot_layout_lookup_accelerator_t *accels;
};

struct GPOSProxy
{
  static const unsigned int table_index = 1;
B
Behdad Esfahbod 已提交
850
  static const bool inplace = true;
B
Behdad Esfahbod 已提交
851 852 853 854 855 856 857 858 859 860 861
  typedef OT::PosLookup Lookup;

  GPOSProxy (hb_face_t *face) :
    table (*hb_ot_layout_from_face (face)->gpos),
    accels (hb_ot_layout_from_face (face)->gpos_accels) {}

  const OT::GPOS &table;
  const hb_ot_layout_lookup_accelerator_t *accels;
};


862 863 864 865 866 867 868 869 870 871 872 873
template <typename Obj>
static inline bool
apply_forward (OT::hb_apply_context_t *c,
	       const Obj &obj,
	       const hb_ot_layout_lookup_accelerator_t &accel)
{
  bool ret = false;
  hb_buffer_t *buffer = c->buffer;
  while (buffer->idx < buffer->len)
  {
    if (accel.may_have (buffer->cur().codepoint) &&
	(buffer->cur().mask & c->lookup_mask) &&
B
Minor  
Behdad Esfahbod 已提交
874
	c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
	obj.apply (c))
      ret = true;
    else
      buffer->next_glyph ();
  }
  return ret;
}

template <typename Obj>
static inline bool
apply_backward (OT::hb_apply_context_t *c,
		const Obj &obj,
		const hb_ot_layout_lookup_accelerator_t &accel)
{
  bool ret = false;
  hb_buffer_t *buffer = c->buffer;
  do
  {
    if (accel.may_have (buffer->cur().codepoint) &&
	(buffer->cur().mask & c->lookup_mask) &&
B
Minor  
Behdad Esfahbod 已提交
895
	c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
896 897 898 899 900 901 902 903 904 905
	obj.apply (c))
      ret = true;
    /* The reverse lookup doesn't "advance" cursor (for good reason). */
    buffer->idx--;

  }
  while ((int) buffer->idx >= 0);
  return ret;
}

906 907
struct hb_apply_forward_context_t
{
B
Behdad Esfahbod 已提交
908
  inline const char *get_name (void) { return "APPLY_FWD"; }
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928
  static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
  typedef bool return_t;
  template <typename T, typename F>
  inline bool may_dispatch (const T *obj, const F *format) { return true; }
  template <typename T>
  inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
  static return_t default_return_value (void) { return false; }
  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }

  hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
			      const hb_ot_layout_lookup_accelerator_t &accel_) :
				c (c_),
				accel (accel_),
				debug_depth (0) {}

  OT::hb_apply_context_t *c;
  const hb_ot_layout_lookup_accelerator_t &accel;
  unsigned int debug_depth;
};

929
template <typename Proxy>
930
static inline void
931 932 933 934
apply_string (OT::hb_apply_context_t *c,
	      const typename Proxy::Lookup &lookup,
	      const hb_ot_layout_lookup_accelerator_t &accel)
{
B
Behdad Esfahbod 已提交
935
  hb_buffer_t *buffer = c->buffer;
936

B
Behdad Esfahbod 已提交
937
  if (unlikely (!buffer->len || !c->lookup_mask))
938
    return;
939 940 941 942 943 944 945

  c->set_lookup (lookup);

  if (likely (!lookup.is_reverse ()))
  {
    /* in/out forward substitution/positioning */
    if (Proxy::table_index == 0)
B
Behdad Esfahbod 已提交
946 947
      buffer->clear_output ();
    buffer->idx = 0;
948

949 950 951 952 953 954 955 956 957
    bool ret;
    if (lookup.get_subtable_count () == 1)
    {
      hb_apply_forward_context_t c_forward (c, accel);
      ret = lookup.dispatch (&c_forward);
    }
    else
      ret = apply_forward (c, lookup, accel);
    if (ret)
958
    {
B
Behdad Esfahbod 已提交
959
      if (!Proxy::inplace)
B
Behdad Esfahbod 已提交
960
	buffer->swap_buffers ();
961
      else
962
	assert (!buffer->has_separate_output ());
963
    }
964 965 966 967 968
  }
  else
  {
    /* in-place backward substitution/positioning */
    if (Proxy::table_index == 0)
B
Behdad Esfahbod 已提交
969 970
      buffer->remove_output ();
    buffer->idx = buffer->len - 1;
971

972
    apply_backward (c, lookup, accel);
973 974 975
  }
}

B
Behdad Esfahbod 已提交
976 977
template <typename Proxy>
inline void hb_ot_map_t::apply (const Proxy &proxy,
B
Behdad Esfahbod 已提交
978 979 980 981
				const hb_ot_shape_plan_t *plan,
				hb_font_t *font,
				hb_buffer_t *buffer) const
{
B
Behdad Esfahbod 已提交
982
  const unsigned int table_index = proxy.table_index;
B
Behdad Esfahbod 已提交
983
  unsigned int i = 0;
B
Behdad Esfahbod 已提交
984
  OT::hb_apply_context_t c (table_index, font, buffer);
985
  c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
B
Behdad Esfahbod 已提交
986 987 988 989

  for (unsigned int stage_index = 0; stage_index < stages[table_index].len; stage_index++) {
    const stage_map_t *stage = &stages[table_index][stage_index];
    for (; i < stage->last_lookup; i++)
B
Behdad Esfahbod 已提交
990 991 992 993
    {
      unsigned int lookup_index = lookups[table_index][i].index;
      c.set_lookup_mask (lookups[table_index][i].mask);
      c.set_auto_zwj (lookups[table_index][i].auto_zwj);
994 995 996
      apply_string<Proxy> (&c,
			   proxy.table.get_lookup (lookup_index),
			   proxy.accels[lookup_index]);
B
Behdad Esfahbod 已提交
997
    }
B
Behdad Esfahbod 已提交
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008

    if (stage->pause_func)
    {
      buffer->clear_output ();
      stage->pause_func (plan, font, buffer);
    }
  }
}

void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
{
B
Behdad Esfahbod 已提交
1009 1010
  GSUBProxy proxy (font->face);
  apply (proxy, plan, font, buffer);
B
Behdad Esfahbod 已提交
1011 1012 1013 1014
}

void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const
{
B
Behdad Esfahbod 已提交
1015 1016 1017 1018 1019 1020 1021 1022 1023
  GPOSProxy proxy (font->face);
  apply (proxy, plan, font, buffer);
}

HB_INTERNAL void
hb_ot_layout_substitute_lookup (OT::hb_apply_context_t *c,
				const OT::SubstLookup &lookup,
				const hb_ot_layout_lookup_accelerator_t &accel)
{
1024
  apply_string<GSUBProxy> (c, lookup, accel);
B
Behdad Esfahbod 已提交
1025
}