hb-ot-layout.cc 25.5 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"
B
Behdad Esfahbod 已提交
36

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

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

B
Behdad Esfahbod 已提交
42

43
HB_SHAPER_DATA_ENSURE_DECLARE(ot, face)
44

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

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

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

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

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

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

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

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

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

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

89 90 91 92 93 94 95
  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);
96

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

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

119

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

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

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

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

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

166

167 168 169 170
/*
 * GSUB/GPOS
 */

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

333 334
  return l.has_required_feature ();
}
335

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

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

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

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

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

  return ret;
373 374 375 376
}


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

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

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

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

B
Behdad Esfahbod 已提交
413
  return f.get_lookup_indexes (start_offset, lookup_count, lookup_indexes);
414 415
}

416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
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 */)
{
449 450 451 452 453 454
  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 已提交
455 456 457 458
    _hb_ot_layout_collect_lookups_lookups (face,
					   table_tag,
					   required_feature_index,
					   lookup_indexes);
459

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
629 630

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

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

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

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

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

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

void
673
hb_ot_layout_substitute_finish (hb_font_t *font, hb_buffer_t *buffer)
674
{
675
  OT::GSUB::substitute_finish (font, buffer);
676 677
}

B
Behdad Esfahbod 已提交
678
void
679
hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
680 681
				        unsigned int  lookup_index,
				        hb_set_t     *glyphs)
682
{
683 684 685 686 687
  OT::hb_closure_context_t c (face, glyphs);

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

  l.closure (&c);
688
}
689

690
/*
691
 * OT::GPOS
692 693 694
 */

hb_bool_t
695 696
hb_ot_layout_has_positioning (hb_face_t *face)
{
697
  return &_get_gpos (face) != &OT::Null(OT::GPOS);
698 699
}

700
void
701
hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer)
702
{
703
  OT::GPOS::position_start (font, buffer);
704 705
}

706
void
707
hb_ot_layout_position_finish (hb_font_t *font, hb_buffer_t *buffer)
708
{
709
  OT::GPOS::position_finish (font, buffer);
710
}
711 712

hb_bool_t
713 714 715 716 717 718
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 */)
719 720
{
  const OT::GPOS &gpos = _get_gpos (face);
721
  const hb_tag_t tag = HB_TAG ('s','i','z','e');
722

723 724 725
  unsigned int num_features = gpos.get_feature_count ();
  for (unsigned int i = 0; i < num_features; i++)
  {
726
    if (tag == gpos.get_feature_tag (i))
727
    {
728
      const OT::Feature &f = gpos.get_feature (i);
729
      const OT::FeatureParamsSize &params = f.get_feature_params ().get_size_params (tag);
730

731
      if (params.designSize)
732
      {
733
#define PARAM(a, A) if (a) *a = params.A
734 735 736 737 738 739
	PARAM (design_size, designSize);
	PARAM (subfamily_id, subfamilyID);
	PARAM (subfamily_name_id, subfamilyNameID);
	PARAM (range_start, rangeStart);
	PARAM (range_end, rangeEnd);
#undef PARAM
740 741 742

	return true;
      }
743 744 745
    }
  }

746
#define PARAM(a, A) if (a) *a = 0
747 748 749 750 751
  PARAM (design_size, designSize);
  PARAM (subfamily_id, subfamilyID);
  PARAM (subfamily_name_id, subfamilyNameID);
  PARAM (range_start, rangeStart);
  PARAM (range_end, rangeEnd);
752
#undef PARAM
753

754
  return false;
755
}
B
Behdad Esfahbod 已提交
756 757 758


/*
B
Behdad Esfahbod 已提交
759
 * Parts of different types are implemented here such that they have direct
B
Behdad Esfahbod 已提交
760 761 762 763
 * access to GSUB/GPOS lookups.
 */


B
Behdad Esfahbod 已提交
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
struct GSUBProxy
{
  static const unsigned int table_index = 0;
  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;
  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;
};


791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
template <typename Lookup>
static inline bool apply_once (OT::hb_apply_context_t *c,
			       const Lookup &lookup)
{
  if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
    return false;
  return lookup.dispatch (c);
}

template <typename Proxy>
static inline bool
apply_string (OT::hb_apply_context_t *c,
	      const typename Proxy::Lookup &lookup,
	      const hb_ot_layout_lookup_accelerator_t &accel)
{
  bool ret = false;

  if (unlikely (!c->buffer->len || !c->lookup_mask))
    return false;

  c->set_lookup (lookup);

  if (likely (!lookup.is_reverse ()))
  {
    /* in/out forward substitution/positioning */
    if (Proxy::table_index == 0)
      c->buffer->clear_output ();
    c->buffer->idx = 0;

    while (c->buffer->idx < c->buffer->len)
    {
      if (accel.digest.may_have (c->buffer->cur().codepoint) &&
	  (c->buffer->cur().mask & c->lookup_mask) &&
	  apply_once (c, lookup))
	ret = true;
      else
	c->buffer->next_glyph ();
    }
    if (ret && Proxy::table_index == 0)
	c->buffer->swap_buffers ();
  }
  else
  {
    /* in-place backward substitution/positioning */
    if (Proxy::table_index == 0)
      c->buffer->remove_output ();
    c->buffer->idx = c->buffer->len - 1;
    do
    {
      if (accel.digest.may_have (c->buffer->cur().codepoint) &&
	  (c->buffer->cur().mask & c->lookup_mask) &&
	  apply_once (c, lookup))
	ret = true;
      else
	c->buffer->idx--;

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

  return ret;
}

B
Behdad Esfahbod 已提交
854 855
template <typename Proxy>
inline void hb_ot_map_t::apply (const Proxy &proxy,
B
Behdad Esfahbod 已提交
856 857 858 859
				const hb_ot_shape_plan_t *plan,
				hb_font_t *font,
				hb_buffer_t *buffer) const
{
B
Behdad Esfahbod 已提交
860
  const unsigned int table_index = proxy.table_index;
B
Behdad Esfahbod 已提交
861
  unsigned int i = 0;
B
Behdad Esfahbod 已提交
862
  OT::hb_apply_context_t c (table_index, font, buffer);
863
  c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
B
Behdad Esfahbod 已提交
864 865 866 867

  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 已提交
868 869 870 871
    {
      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);
872 873 874
      apply_string<Proxy> (&c,
			   proxy.table.get_lookup (lookup_index),
			   proxy.accels[lookup_index]);
B
Behdad Esfahbod 已提交
875
    }
B
Behdad Esfahbod 已提交
876 877 878 879 880 881 882 883 884 885 886

    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 已提交
887 888
  GSUBProxy proxy (font->face);
  apply (proxy, plan, font, buffer);
B
Behdad Esfahbod 已提交
889 890 891 892
}

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 已提交
893 894 895 896 897 898 899 900 901
  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)
{
902
  apply_string<GSUBProxy> (c, lookup, accel);
B
Behdad Esfahbod 已提交
903
}