hb-ot-layout-gsub-private.h 25.0 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
2
 * Copyright (C) 2007,2008,2009  Red Hat, Inc.
B
Behdad Esfahbod 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 *  This is part of HarfBuzz, an OpenType Layout engine library.
 *
 * 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
 */

#ifndef HB_OT_LAYOUT_GSUB_PRIVATE_H
#define HB_OT_LAYOUT_GSUB_PRIVATE_H

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

struct SingleSubstFormat1 {
B
Behdad Esfahbod 已提交
33 34 35 36

  friend struct SingleSubst;

  private:
B
Behdad Esfahbod 已提交
37

38
  inline bool single_substitute (hb_codepoint_t &glyph_id) const {
B
Behdad Esfahbod 已提交
39

B
Behdad Esfahbod 已提交
40
    unsigned int index = (this+coverage) (glyph_id);
41
    if (NOT_COVERED == index)
B
Behdad Esfahbod 已提交
42 43 44 45 46
      return false;

    glyph_id += deltaGlyphID;

    return true;
47
  }
B
Behdad Esfahbod 已提交
48

B
Behdad Esfahbod 已提交
49 50
  private:
  USHORT	substFormat;		/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
51 52
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
53 54 55 56 57 58 59
					 * beginning of Substitution table */
  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
					 * substitute GlyphID */
};
ASSERT_SIZE (SingleSubstFormat1, 6);

struct SingleSubstFormat2 {
60 61 62 63 64 65 66

  friend struct SingleSubst;

  private:

  inline bool single_substitute (hb_codepoint_t &glyph_id) const {

B
Behdad Esfahbod 已提交
67
    unsigned int index = (this+coverage) (glyph_id);
68

B
Behdad Esfahbod 已提交
69
    if (index >= substitute.len)
70 71 72 73 74
      return false;

    glyph_id = substitute[index];
    return true;
  }
B
Behdad Esfahbod 已提交
75 76 77

  private:
  USHORT	substFormat;		/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
78 79
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
80
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
81 82 83
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
B
Behdad Esfahbod 已提交
84 85 86
};
ASSERT_SIZE (SingleSubstFormat2, 6);

87 88 89 90
struct SingleSubst {

  friend struct SubstLookupSubTable;

91 92
  private:

B
Behdad Esfahbod 已提交
93 94 95 96 97 98 99 100
  inline bool single_substitute (hb_codepoint_t &glyph_id) const {
    switch (u.substFormat) {
    case 1: return u.format1.single_substitute (glyph_id);
    case 2: return u.format2.single_substitute (glyph_id);
    default:return false;
    }
  }

B
Behdad Esfahbod 已提交
101
  inline bool substitute (LOOKUP_ARGS_DEF) const {
102

103
    unsigned int property;
104 105 106
    if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
      return false;

107
    hb_codepoint_t glyph_id = IN_CURGLYPH ();
108

B
Behdad Esfahbod 已提交
109 110
    if (!single_substitute (glyph_id))
      return false;
111

B
Behdad Esfahbod 已提交
112
    _hb_buffer_replace_glyph (buffer, glyph_id);
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128

    if ( _hb_ot_layout_has_new_glyph_classes (layout) )
    {
      /* we inherit the old glyph class to the substituted glyph */
      _hb_ot_layout_set_glyph_property (layout, glyph_id, property);
    }

    return true;
  }

  private:
  union {
  USHORT	substFormat;	/* Format identifier */
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
  } u;
B
Behdad Esfahbod 已提交
129
};
130 131
DEFINE_NULL (SingleSubst, 2);

B
Behdad Esfahbod 已提交
132 133

struct Sequence {
134 135 136 137 138 139 140

  friend struct MultipleSubstFormat1;

  private:

  inline void set_glyph_class (hb_ot_layout_t *layout, unsigned int property) const {

B
Behdad Esfahbod 已提交
141
    unsigned int count = substitute.len;
142
    for (unsigned int n = 0; n < count; n++)
143 144
      _hb_ot_layout_set_glyph_property (layout, substitute[n], property);
  }
B
Behdad Esfahbod 已提交
145

B
Behdad Esfahbod 已提交
146
  inline bool substitute_sequence (LOOKUP_ARGS_DEF, unsigned int property) const {
B
Behdad Esfahbod 已提交
147

B
Behdad Esfahbod 已提交
148
    if (HB_UNLIKELY (!substitute.len))
B
Behdad Esfahbod 已提交
149 150 151
      return false;

    _hb_buffer_add_output_glyph_ids (buffer, 1,
B
Behdad Esfahbod 已提交
152
				     substitute.len, substitute.array,
B
Behdad Esfahbod 已提交
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
				     0xFFFF, 0xFFFF);

    if ( _hb_ot_layout_has_new_glyph_classes (layout) )
    {
      /* this is a guess only ... */

      if ( property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE )
        property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;

      set_glyph_class (layout, property);
    }

    return true;
  }

B
Behdad Esfahbod 已提交
168
  private:
B
Behdad Esfahbod 已提交
169 170
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
B
Behdad Esfahbod 已提交
171
};
172
ASSERT_SIZE (Sequence, 2);
B
Behdad Esfahbod 已提交
173

174 175 176 177 178 179
struct MultipleSubstFormat1 {

  friend struct MultipleSubst;

  private:

B
Behdad Esfahbod 已提交
180
  inline bool substitute (LOOKUP_ARGS_DEF) const {
181

182
    unsigned int property;
183 184 185
    if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
      return false;

B
Behdad Esfahbod 已提交
186
    unsigned int index = (this+coverage) (IN_CURGLYPH ());
B
Behdad Esfahbod 已提交
187
    return (this+sequence[index]).substitute_sequence (LOOKUP_ARGS, property);
188
  }
B
Behdad Esfahbod 已提交
189 190 191

  private:
  USHORT	substFormat;		/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
192 193
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
194
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
195 196 197
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
B
Behdad Esfahbod 已提交
198
};
199 200 201 202
ASSERT_SIZE (MultipleSubstFormat1, 6);

struct MultipleSubst {

203 204 205 206
  friend struct SubstLookupSubTable;

  private:

B
Behdad Esfahbod 已提交
207
  inline bool substitute (LOOKUP_ARGS_DEF) const {
208
    switch (u.substFormat) {
B
Behdad Esfahbod 已提交
209
    case 1: return u.format1.substitute (LOOKUP_ARGS);
210 211 212 213 214 215 216 217 218 219 220 221
    default:return false;
    }
  }

  private:
  union {
  USHORT	substFormat;	/* Format identifier */
  MultipleSubstFormat1	format1;
  } u;
};
DEFINE_NULL (MultipleSubst, 2);

B
Behdad Esfahbod 已提交
222

B
Behdad Esfahbod 已提交
223
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
224
					 * arbitrary order */
225
ASSERT_SIZE (AlternateSet, 2);
B
Behdad Esfahbod 已提交
226

227
struct AlternateSubstFormat1 {
228 229 230 231 232

  friend struct AlternateSubst;

  private:

B
Behdad Esfahbod 已提交
233
  inline bool substitute (LOOKUP_ARGS_DEF) const {
234

235
    unsigned int property;
236 237 238
    if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
      return false;

239
    hb_codepoint_t glyph_id = IN_CURGLYPH ();
240

B
Behdad Esfahbod 已提交
241
    unsigned int index = (this+coverage) (glyph_id);
B
Behdad Esfahbod 已提交
242
    const AlternateSet &alt_set = this+alternateSet[index];
243

B
Behdad Esfahbod 已提交
244
    if (HB_UNLIKELY (!alt_set.len))
245 246 247 248 249 250 251 252 253 254 255
      return false;

    unsigned int alt_index = 0;

    /* XXX callback to user to choose alternate
    if ( gsub->altfunc )
      alt_index = (gsub->altfunc)( buffer->out_pos, glyph_id,
				   aset.GlyphCount, aset.Alternate,
				   gsub->data );
				   */

B
Behdad Esfahbod 已提交
256
    if (HB_UNLIKELY (alt_index >= alt_set.len))
257 258 259 260
      return false;

    glyph_id = alt_set[alt_index];

B
Behdad Esfahbod 已提交
261
    _hb_buffer_replace_glyph (buffer, glyph_id);
262 263 264 265 266 267 268 269 270

    if ( _hb_ot_layout_has_new_glyph_classes (layout) )
    {
      /* we inherit the old glyph class to the substituted glyph */
      _hb_ot_layout_set_glyph_property (layout, glyph_id, property);
    }

    return true;
  }
B
Behdad Esfahbod 已提交
271 272 273

  private:
  USHORT	substFormat;		/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
274 275
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
276
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
277 278 279
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
B
Behdad Esfahbod 已提交
280
};
281 282
ASSERT_SIZE (AlternateSubstFormat1, 6);

283 284 285 286 287 288
struct AlternateSubst {

  friend struct SubstLookupSubTable;

  private:

B
Behdad Esfahbod 已提交
289
  inline bool substitute (LOOKUP_ARGS_DEF) const {
290
    switch (u.substFormat) {
B
Behdad Esfahbod 已提交
291
    case 1: return u.format1.substitute (LOOKUP_ARGS);
292 293 294 295 296 297 298 299 300 301 302 303
    default:return false;
    }
  }

  private:
  union {
  USHORT	substFormat;	/* Format identifier */
  AlternateSubstFormat1	format1;
  } u;
};
DEFINE_NULL (AlternateSubst, 2);

304 305

struct Ligature {
306 307 308 309 310 311

  friend struct LigatureSet;

  private:
  DEFINE_ARRAY_TYPE (GlyphID, component, (compCount ? compCount - 1 : 0));

B
Behdad Esfahbod 已提交
312
  inline bool substitute_ligature (LOOKUP_ARGS_DEF, bool is_mark) const {
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376

    unsigned int i, j;
    unsigned int property;
    unsigned int count = compCount;

    if (HB_UNLIKELY (buffer->in_pos + count > buffer->in_length ||
		     context_length < count))
      return false; /* Not enough glyphs in input or context */

    for (i = 1, j = buffer->in_pos + 1; i < count; i++, j++) {
      while (!_hb_ot_layout_check_glyph_property (layout, IN_ITEM (j), lookup_flag, &property)) {
	if (HB_UNLIKELY (j + count - i == buffer->in_length))
	  return false;
	j++;
      }

      if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK ||
	    property &  LookupFlag::MarkAttachmentType))
	is_mark = FALSE;

      if (HB_LIKELY (IN_GLYPH(j) != (*this)[i - 1]))
        return false;
    }
    if ( _hb_ot_layout_has_new_glyph_classes (layout) )
      /* this is just a guess ... */
      hb_ot_layout_set_glyph_class (layout, ligGlyph,
				    is_mark ? HB_OT_LAYOUT_GLYPH_CLASS_MARK
					    : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);

    if (j == buffer->in_pos + i) /* No input glyphs skipped */
      /* We don't use a new ligature ID if there are no skipped
	 glyphs and the ligature already has an ID. */
      _hb_buffer_add_output_glyph_ids (buffer, i,
				       1, &ligGlyph,
				       0xFFFF,
				       IN_LIGID (buffer->in_pos) ?
				       0xFFFF : _hb_buffer_allocate_ligid (buffer));
    else
    {
      unsigned int lig_id = _hb_buffer_allocate_ligid (buffer);
      _hb_buffer_add_output_glyph (buffer, ligGlyph, 0xFFFF, lig_id);

      /* Now we must do a second loop to copy the skipped glyphs to
	 `out' and assign component values to it.  We start with the
	 glyph after the first component.  Glyphs between component
	 i and i+1 belong to component i.  Together with the lig_id
	 value it is later possible to check whether a specific
	 component value really belongs to a given ligature. */

      for ( i = 0; i < count - 1; i++ )
      {
	while (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM(), lookup_flag, &property))
	  _hb_buffer_add_output_glyph (buffer, IN_CURGLYPH(), i, lig_id);

	(buffer->in_pos)++;
      }

      /* XXX We  should possibly reassign lig_id and component for any
       * components of a previous ligature that s now being removed as part of
       * this ligature. */
    }

    return true;
  }
377 378 379 380 381 382 383 384

  private:
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
  USHORT	compCount;		/* Number of components in the ligature */
  GlyphID	component[];		/* Array of component GlyphIDs--start
					 * with the second  component--ordered
					 * in writing direction */
};
385
ASSERT_SIZE (Ligature, 4);
B
Behdad Esfahbod 已提交
386 387

struct LigatureSet {
388 389 390 391 392

  friend struct LigatureSubstFormat1;

  private:

B
Behdad Esfahbod 已提交
393
  inline bool substitute_ligature (LOOKUP_ARGS_DEF, bool is_mark) const {
394

B
Behdad Esfahbod 已提交
395
    unsigned int num_ligs = ligature.len;
396
    for (unsigned int i = 0; i < num_ligs; i++) {
B
Behdad Esfahbod 已提交
397
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
398
      if (lig.substitute_ligature (LOOKUP_ARGS, is_mark))
399 400 401 402 403
        return true;
    }

    return false;
  }
B
Behdad Esfahbod 已提交
404 405

  private:
B
Behdad Esfahbod 已提交
406 407 408
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
B
Behdad Esfahbod 已提交
409
};
410
ASSERT_SIZE (LigatureSet, 2);
B
Behdad Esfahbod 已提交
411

412
struct LigatureSubstFormat1 {
413 414 415 416 417

  friend struct LigatureSubst;

  private:

B
Behdad Esfahbod 已提交
418
  inline bool substitute (LOOKUP_ARGS_DEF) const {
419 420 421 422 423 424 425 426 427 428

    unsigned int property;
    if (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM (), lookup_flag, &property))
      return false;

    hb_codepoint_t glyph_id = IN_CURGLYPH ();

    bool first_is_mark = (property == HB_OT_LAYOUT_GLYPH_CLASS_MARK ||
			  property &  LookupFlag::MarkAttachmentType);

B
Behdad Esfahbod 已提交
429 430
    unsigned int index = (this+coverage) (glyph_id);
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
431
    return lig_set.substitute_ligature (LOOKUP_ARGS, first_is_mark);
432
  }
B
Behdad Esfahbod 已提交
433 434

  private:
435
  USHORT	substFormat;		/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
436 437
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
438
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
439 440 441
  OffsetArrayOf<LigatureSet>\
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
B
Behdad Esfahbod 已提交
442
};
443 444
ASSERT_SIZE (LigatureSubstFormat1, 6);

445 446 447 448 449 450
struct LigatureSubst {

  friend struct SubstLookupSubTable;

  private:

B
Behdad Esfahbod 已提交
451
  inline bool substitute (LOOKUP_ARGS_DEF) const {
452
    switch (u.substFormat) {
B
Behdad Esfahbod 已提交
453
    case 1: return u.format1.substitute (LOOKUP_ARGS);
454 455 456 457 458 459 460 461 462 463 464 465
    default:return false;
    }
  }

  private:
  union {
  USHORT	substFormat;	/* Format identifier */
  LigatureSubstFormat1	format1;
  } u;
};
DEFINE_NULL (LigatureSubst, 2);

B
Behdad Esfahbod 已提交
466

467

468
static inline bool substitute_lookup (LOOKUP_ARGS_DEF, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
469

470
struct ContextSubst : Context {
B
Behdad Esfahbod 已提交
471

472
  inline bool substitute (LOOKUP_ARGS_DEF) const {
473
    return this->apply (LOOKUP_ARGS, substitute_lookup);
474 475
  }
};
476 477 478
DEFINE_NULL (ContextSubst, 2);


B
Behdad Esfahbod 已提交
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
struct ChainSubRule {
  /* TODO */

  private:
  USHORT	backtrackGlyphCount;	/* Total number of glyphs in the
					 * backtrack sequence (number of
					 * glyphs to be matched before the
					 * first glyph) */
  GlyphID	backtrack[];		/* Array of backtracking GlyphID's
					 * (to be matched before the input
					 * sequence) */
  USHORT	inputGlyphCount;	/* Total number of glyphs in the input
					 * sequence (includes the first  glyph) */
  GlyphID	input[];		/* Array of input GlyphIDs (start with
					 * second glyph) */
  USHORT	lookaheadGlyphCount;	/* Total number of glyphs in the look
					 * ahead sequence (number of  glyphs to
					 * be matched after the input sequence) */
  GlyphID	lookAhead[];		/* Array of lookahead GlyphID's (to be
					 * matched after  the input sequence) */
499 500
  USHORT	substCount;		/* Number of LookupRecords */
  LookupRecord	substLookupRecord[];	/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
501 502
					 * design order) */
};
503
ASSERT_SIZE (ChainSubRule, 8);
B
Behdad Esfahbod 已提交
504

B
Behdad Esfahbod 已提交
505
struct ChainSubRuleSet {
B
Behdad Esfahbod 已提交
506 507 508
  /* TODO */

  private:
B
Behdad Esfahbod 已提交
509 510
  USHORT	chainSubRuleCount;	/* Number of ChainSubRule tables */
  Offset	chainSubRule[];		/* Array of offsets to ChainSubRule
B
Behdad Esfahbod 已提交
511
					 * tables--from beginning of
B
Behdad Esfahbod 已提交
512 513
					 * ChainSubRuleSet table--ordered
					 * by preference */
B
Behdad Esfahbod 已提交
514
};
515
ASSERT_SIZE (ChainSubRuleSet, 2);
B
Behdad Esfahbod 已提交
516

B
Behdad Esfahbod 已提交
517
struct ChainContextSubstFormat1 {
B
Behdad Esfahbod 已提交
518
  /* TODO */
B
Behdad Esfahbod 已提交
519
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
520 521
    return false;
  }
B
Behdad Esfahbod 已提交
522 523

  private:
B
Behdad Esfahbod 已提交
524 525 526 527 528 529 530
  USHORT	substFormat;		/* Format identifier--format = 1 */
  Offset	coverage;		/* Offset to Coverage table--from
					 * beginning of Substitution table */
  USHORT	chainSubRuleSetCount;	/* Number of ChainSubRuleSet
					 * tables--must equal GlyphCount in
					 * Coverage table */
  Offset	chainSubRuleSet[];	/* Array of offsets to ChainSubRuleSet
B
Behdad Esfahbod 已提交
531
					 * tables--from beginning of
B
Behdad Esfahbod 已提交
532 533
					 * Substitution table--ordered by
					 * Coverage Index */
B
Behdad Esfahbod 已提交
534
};
B
Behdad Esfahbod 已提交
535
ASSERT_SIZE (ChainContextSubstFormat1, 6);
B
Behdad Esfahbod 已提交
536 537 538 539 540 541 542 543 544

struct ChainSubClassRule {
  /* TODO */

  private:
  USHORT	backtrackGlyphCount;	/* Total number of glyphs in the
					 * backtrack sequence (number of
					 * glyphs to be matched before the
					 * first glyph) */
B
Behdad Esfahbod 已提交
545
  USHORT	backtrack[];		/* Array of backtracking classes (to be
B
Behdad Esfahbod 已提交
546 547 548 549 550 551 552 553 554 555
					 * matched before the input  sequence) */
  USHORT	inputGlyphCount;	/* Total number of classes in the input
					 * sequence (includes the  first class) */
  USHORT	input[];		/* Array of input classes(start with
					 * second class; to  be matched with
					 * the input glyph sequence) */
  USHORT	lookaheadGlyphCount;	/* Total number of classes in the
					 * look ahead sequence (number of
					 * classes to be matched after the
					 * input sequence) */
B
Behdad Esfahbod 已提交
556
  USHORT	lookAhead[];		/* Array of lookahead classes (to be
B
Behdad Esfahbod 已提交
557
					 * matched after the  input sequence) */
558 559
  USHORT	substCount;		/* Number of LookupRecords */
  LookupRecord	substLookupRecord[];	/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
560 561
					 * design order) */
};
562
ASSERT_SIZE (ChainSubClassRule, 8);
B
Behdad Esfahbod 已提交
563

B
Behdad Esfahbod 已提交
564 565 566 567 568 569 570 571 572 573 574
struct ChainSubClassSet {
  /* TODO */

  private:
  USHORT	chainSubClassRuleCnt;	/* Number of ChainSubClassRule tables */
  Offset	chainSubClassRule[];	/* Array of offsets
					 * to ChainSubClassRule
					 * tables--from beginning of
					 * ChainSubClassSet--ordered by
					 * preference */
};
575
ASSERT_SIZE (ChainSubClassSet, 2);
B
Behdad Esfahbod 已提交
576 577 578

struct ChainContextSubstFormat2 {
  /* TODO */
B
Behdad Esfahbod 已提交
579
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
580 581
    return false;
  }
B
Behdad Esfahbod 已提交
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606

  private:
  USHORT	substFormat;		/* Format identifier--format = 2 */
  Offset	coverage;		/* Offset to Coverage table--from
					 * beginning of Substitution table */
  Offset	backtrackClassDef;	/* Offset to glyph ClassDef table
					 * containing backtrack sequence
					 * data--from beginning of Substitution
					 * table */
  Offset	inputClassDef;		/* Offset to glyph ClassDef
					 * table containing input sequence
					 * data--from beginning of Substitution
					 * table */
  Offset	lookaheadClassDef;	/* Offset to glyph ClassDef table
					 * containing lookahead sequence
					 * data--from beginning of Substitution
					 * table */
  USHORT	chainSubClassSetCnt;	/* Number of ChainSubClassSet tables */
  Offset	chainSubClassSet[];	/* Array of offsets to ChainSubClassSet
					 * tables--from beginning of
					 * Substitution table--ordered by input
					 * class--may be NULL */
};
ASSERT_SIZE (ChainContextSubstFormat2, 12);

B
Behdad Esfahbod 已提交
607 608
struct ChainContextSubstFormat3 {
  /* TODO */
B
Behdad Esfahbod 已提交
609
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
610 611
    return false;
  }
B
Behdad Esfahbod 已提交
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628

  private:
  USHORT	substFormat;		/* Format identifier--format = 3 */
  USHORT	backtrackGlyphCount;	/* Number of glyphs in the backtracking
					 * sequence */
  Offset	backtrackCoverage[];	/* Array of offsets to coverage tables
					 * in backtracking sequence, in  glyph
					 * sequence order */
  USHORT	inputGlyphCount;	/* Number of glyphs in input sequence */
  Offset	inputCoverage[];	/* Array of offsets to coverage
					 * tables in input sequence, in glyph
					 * sequence order */
  USHORT	lookaheadGlyphCount;	/* Number of glyphs in lookahead
					 * sequence */
  Offset	lookaheadCoverage[];	/* Array of offsets to coverage tables
					 * in lookahead sequence, in  glyph
					 * sequence order */
629 630
  USHORT	substCount;		/* Number of LookupRecords */
  LookupRecord	substLookupRecord[];	/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
631 632 633 634
					 * design order */
};
ASSERT_SIZE (ChainContextSubstFormat3, 10);

B
Behdad Esfahbod 已提交
635 636 637 638 639 640
struct ChainContextSubst {

  friend struct SubstLookupSubTable;

  private:

B
Behdad Esfahbod 已提交
641
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
642
    switch (u.substFormat) {
B
Behdad Esfahbod 已提交
643 644 645
    case 1: return u.format1.substitute (LOOKUP_ARGS);
    case 2: return u.format2.substitute (LOOKUP_ARGS);
    case 3: return u.format3.substitute (LOOKUP_ARGS);
B
Behdad Esfahbod 已提交
646 647 648 649 650 651 652 653 654 655 656 657 658 659
    default:return false;
    }
  }

  private:
  union {
  USHORT	substFormat;	/* Format identifier */
  ChainContextSubstFormat1	format1;
  ChainContextSubstFormat2	format2;
  ChainContextSubstFormat3	format3;
  } u;
};
DEFINE_NULL (ChainContextSubst, 2);

660

B
Behdad Esfahbod 已提交
661
struct ExtensionSubstFormat1 {
662 663 664 665 666

  friend struct ExtensionSubst;

  private:
  inline unsigned int get_type (void) const { return extensionLookupType; }
B
Behdad Esfahbod 已提交
667
  inline bool substitute (LOOKUP_ARGS_DEF) const;
B
Behdad Esfahbod 已提交
668 669 670 671 672 673 674 675 676 677 678

  private:
  USHORT	substFormat;		/* Format identifier. Set to 1. */
  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
					 * by ExtensionOffset (i.e. the
					 * extension subtable). */
  ULONG		extensionOffset;	/* Offset to the extension subtable,
					 * of lookup type  subtable. */
};
ASSERT_SIZE (ExtensionSubstFormat1, 8);

679 680 681 682 683 684 685 686 687 688 689 690 691 692
struct ExtensionSubst {

  friend struct SubstLookup;
  friend struct SubstLookupSubTable;

  private:

  inline unsigned int get_type (void) const {
    switch (u.substFormat) {
    case 1: return u.format1.get_type ();
    default:return 0;
    }
  }

B
Behdad Esfahbod 已提交
693
  inline bool substitute (LOOKUP_ARGS_DEF) const {
694
    switch (u.substFormat) {
B
Behdad Esfahbod 已提交
695
    case 1: return u.format1.substitute (LOOKUP_ARGS);
696 697 698 699 700 701 702 703 704 705 706 707 708 709
    default:return false;
    }
  }

  private:
  union {
  USHORT	substFormat;	/* Format identifier */
  ExtensionSubstFormat1	format1;
  } u;
};
DEFINE_NULL (ExtensionSubst, 2);



B
Behdad Esfahbod 已提交
710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
struct ReverseChainSingleSubstFormat1 {
  /* TODO */

  private:
  USHORT	substFormat;		/* Format identifier--format = 1 */
  Offset	coverage;		/* Offset to Coverage table -- from
					 * beginning of Substitution table */
  USHORT	backtrackGlyphCount;	/* Number of glyphs in the backtracking
					 * sequence */
  Offset	backtrackCoverage[];	/* Array of offsets to coverage tables
					 * in backtracking sequence, in  glyph
					 * sequence order */
  USHORT	lookaheadGlyphCount;	/* Number of glyphs in lookahead
					 * sequence */
  Offset	lookaheadCoverage[];	/* Array of offsets to coverage tables
					 * in lookahead sequence, in  glyph
					 * sequence order */
  USHORT	glyphCount;		/* Number of GlyphIDs in the Substitute
					 * array */
  GlyphID	substitute[];		/* Array of substitute
					 * GlyphIDs--ordered by Coverage  Index */
};
ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);

B
Behdad Esfahbod 已提交
734 735 736 737
/*
 * SubstLookup
 */

738 739 740
enum {
  GSUB_Single				= 1,
  GSUB_Multiple				= 2,
741
  GSUB_Alternate			= 3,
742 743 744
  GSUB_Ligature				= 4,
  GSUB_Context				= 5,
  GSUB_ChainingContext			= 6,
745 746
  GSUB_Extension			= 7,
  GSUB_ReverseChainingContextSingle	= 8,
747 748
};

B
Behdad Esfahbod 已提交
749 750 751 752
struct SubstLookupSubTable {

  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
753
  inline bool substitute (LOOKUP_ARGS_DEF,
754
			  unsigned int    lookup_type) const {
755
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
756 757 758 759 760
    case GSUB_Single:				return u.single.substitute (LOOKUP_ARGS);
    case GSUB_Multiple:				return u.multiple.substitute (LOOKUP_ARGS);
    case GSUB_Alternate:			return u.alternate.substitute (LOOKUP_ARGS);
    case GSUB_Ligature:				return u.ligature.substitute (LOOKUP_ARGS);
    case GSUB_Context:				return u.context.substitute (LOOKUP_ARGS);
761
    /*
B
Behdad Esfahbod 已提交
762
    case GSUB_ChainingContext:			return u.chainingContext.substitute (LOOKUP_ARGS);
763
    */
B
Behdad Esfahbod 已提交
764
    case GSUB_Extension:			return u.extension.substitute (LOOKUP_ARGS);
765
			/*
B
Behdad Esfahbod 已提交
766
    case GSUB_ReverseChainingContextSingle:	return u.reverseChainingContextSingle.substitute (LOOKUP_ARGS);
767 768 769
    */
    default:return false;
    }
B
Behdad Esfahbod 已提交
770 771 772 773
  }

  private:
  union {
774 775 776 777 778 779
  USHORT				substFormat;
  SingleSubst				single;
  MultipleSubst				multiple;
  AlternateSubst			alternate;
  LigatureSubst				ligature;
  ContextSubst				context;
780
  /*
781 782 783 784 785 786
  ChainingContextSubst			chainingContext;
  */
  ExtensionSubst			extension;
  /*
  ReverseChainingContextSingleSubst	reverseChainingContextSingle;
  */
B
Behdad Esfahbod 已提交
787 788 789
  } u;
};

790

B
Behdad Esfahbod 已提交
791 792 793 794 795 796 797
struct SubstLookup : Lookup {

  inline const SubstLookupSubTable& get_subtable (unsigned int i) const {
    return *(SubstLookupSubTable*)&(((Lookup *)this)->get_subtable (i));
  }

  /* Like get_type(), but looks through extension lookups.
798
   * Never returns Extension */
B
Behdad Esfahbod 已提交
799 800 801
  inline unsigned int get_effective_type (void) const {
    unsigned int type = get_type ();

802
    if (HB_UNLIKELY (type == GSUB_Extension)) {
B
Behdad Esfahbod 已提交
803 804 805
      /* Return lookup type of first extension subtable.
       * The spec says all of them should have the same type.
       * XXX check for that somehow */
806
      type = get_subtable(0).u.extension.get_type ();
B
Behdad Esfahbod 已提交
807 808 809 810 811 812 813
    }

    return type;
  }

  inline bool is_reverse (void) const {
    switch (get_effective_type ()) {
814 815
    case GSUB_ReverseChainingContextSingle:	return true;
    default:					return false;
B
Behdad Esfahbod 已提交
816 817 818
    }
  }

819 820 821 822
  bool substitute_once (hb_ot_layout_t *layout,
			hb_buffer_t    *buffer,
			unsigned int    context_length,
			unsigned int    nesting_level_left) const {
823

B
Behdad Esfahbod 已提交
824
    unsigned int lookup_type = get_type ();
B
Behdad Esfahbod 已提交
825
    unsigned int lookup_flag = get_flag ();
B
Behdad Esfahbod 已提交
826 827 828 829

    if (HB_UNLIKELY (nesting_level_left == 0))
      return false;
    nesting_level_left--;
B
Behdad Esfahbod 已提交
830

B
Behdad Esfahbod 已提交
831 832 833
    if (HB_UNLIKELY (context_length < 1))
      return false;

B
Behdad Esfahbod 已提交
834
    for (unsigned int i = 0; i < get_subtable_count (); i++)
B
Behdad Esfahbod 已提交
835
      if (get_subtable (i).substitute (LOOKUP_ARGS,
836
				       lookup_type))
B
Behdad Esfahbod 已提交
837
	return true;
B
Behdad Esfahbod 已提交
838

B
Behdad Esfahbod 已提交
839 840
    return false;
  }
841

842 843 844
  bool substitute_string (hb_ot_layout_t *layout,
			  hb_buffer_t    *buffer,
			  hb_ot_layout_feature_mask_t mask) const {
845 846 847

    bool ret = false;

848
    if (HB_LIKELY (!is_reverse ())) {
849 850 851 852 853 854 855 856 857 858

	/* in/out forward substitution */
	_hb_buffer_clear_output (buffer);
	buffer->in_pos = 0;
	while (buffer->in_pos < buffer->in_length) {

	  if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
	      substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
	    ret = true;
	  else
B
Behdad Esfahbod 已提交
859
	    _hb_buffer_next_glyph (buffer);
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876

	}
	if (ret)
	  _hb_buffer_swap (buffer);

    } else {

	/* in-place backward substitution */
	buffer->in_pos = buffer->in_length - 1;
	do {

	  if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
	      substitute_once (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
	    ret = true;
	  else
	    buffer->in_pos--;

877
	} while ((int) buffer->in_pos >= 0);
878 879 880 881
    }

    return ret;
  }
B
Behdad Esfahbod 已提交
882 883
};

884

B
Minor  
Behdad Esfahbod 已提交
885 886 887 888 889 890 891 892 893
/*
 * GSUB
 */

struct GSUB : GSUBGPOS {
  static const hb_tag_t Tag		= HB_TAG ('G','S','U','B');

  STATIC_DEFINE_GET_FOR_DATA (GSUB);
  /* XXX check version here? */
B
Behdad Esfahbod 已提交
894 895 896 897 898

  inline const SubstLookup& get_lookup (unsigned int i) const {
    return *(SubstLookup*)&(((GSUBGPOS *)this)->get_lookup (i));
  }

899 900 901 902 903 904
  inline bool substitute_lookup (hb_ot_layout_t *layout,
				 hb_buffer_t    *buffer,
			         unsigned int    lookup_index,
				 hb_ot_layout_feature_mask_t  mask) const {
    return get_lookup (lookup_index).substitute_string (layout, buffer, mask);
  }
B
Behdad Esfahbod 已提交
905

B
Minor  
Behdad Esfahbod 已提交
906 907 908
};


909 910 911 912


/* Out-of-class implementation for methods chaining */

B
Behdad Esfahbod 已提交
913
inline bool ExtensionSubstFormat1::substitute (LOOKUP_ARGS_DEF) const {
914 915
  /* XXX either check in sanitize or here that the lookuptype is not 7 again,
   * or we can loop indefinitely. */
B
Behdad Esfahbod 已提交
916
  return (*(SubstLookupSubTable *)(((char *) this) + extensionOffset)).substitute (LOOKUP_ARGS,
917 918 919
										   get_type ());
}

920
static inline bool substitute_lookup (LOOKUP_ARGS_DEF, unsigned int lookup_index) {
921
  const GSUB &gsub = *(layout->gsub);
922
  const SubstLookup &l = gsub.get_lookup (lookup_index);
923 924 925 926 927

  return l.substitute_once (layout, buffer, context_length, nesting_level_left);
}


B
Behdad Esfahbod 已提交
928
#endif /* HB_OT_LAYOUT_GSUB_PRIVATE_H */