hb-ot-layout-gsub-private.h 25.3 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

B
Behdad Esfahbod 已提交
32 33 34 35 36 37 38 39 40 41
/* XXX */
#include "harfbuzz-impl.h"
HB_INTERNAL HB_Error
_hb_buffer_add_output_glyph_ids( HB_Buffer  buffer,
			      HB_UShort  num_in,
			      HB_UShort  num_out,
			      const GlyphID *glyph_data,
			      HB_UShort  component,
			      HB_UShort  ligID );

B
Behdad Esfahbod 已提交
42
struct SingleSubstFormat1 {
B
Behdad Esfahbod 已提交
43 44 45 46

  friend struct SingleSubst;

  private:
B
Behdad Esfahbod 已提交
47

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

B
Behdad Esfahbod 已提交
50
    unsigned int index = (this+coverage) (glyph_id);
51
    if (NOT_COVERED == index)
B
Behdad Esfahbod 已提交
52 53 54 55 56
      return false;

    glyph_id += deltaGlyphID;

    return true;
57
  }
B
Behdad Esfahbod 已提交
58

B
Behdad Esfahbod 已提交
59
  private:
B
Behdad Esfahbod 已提交
60
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
61 62
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
63 64 65 66 67 68 69
					 * beginning of Substitution table */
  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
					 * substitute GlyphID */
};
ASSERT_SIZE (SingleSubstFormat1, 6);

struct SingleSubstFormat2 {
70 71 72 73 74 75 76

  friend struct SingleSubst;

  private:

  inline bool single_substitute (hb_codepoint_t &glyph_id) const {

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

B
Behdad Esfahbod 已提交
79
    if (index >= substitute.len)
80 81 82 83 84
      return false;

    glyph_id = substitute[index];
    return true;
  }
B
Behdad Esfahbod 已提交
85 86

  private:
B
Behdad Esfahbod 已提交
87
  USHORT	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
88 89
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
90
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
91 92 93
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
B
Behdad Esfahbod 已提交
94 95 96
};
ASSERT_SIZE (SingleSubstFormat2, 6);

97 98 99 100
struct SingleSubst {

  friend struct SubstLookupSubTable;

101 102
  private:

B
Behdad Esfahbod 已提交
103
  inline bool single_substitute (hb_codepoint_t &glyph_id) const {
B
Behdad Esfahbod 已提交
104 105 106
    switch (u.format) {
    case 1: return u.format1->single_substitute (glyph_id);
    case 2: return u.format2->single_substitute (glyph_id);
B
Behdad Esfahbod 已提交
107 108 109 110
    default:return false;
    }
  }

111
  inline bool substitute (LOOKUP_ARGS_DEF) const {
112

113
    hb_codepoint_t glyph_id = IN_CURGLYPH ();
114

B
Behdad Esfahbod 已提交
115 116
    if (!single_substitute (glyph_id))
      return false;
117

B
Behdad Esfahbod 已提交
118
    _hb_buffer_replace_glyph (buffer, glyph_id);
119 120 121 122 123 124 125 126 127 128 129 130

    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 {
B
Behdad Esfahbod 已提交
131 132 133
  USHORT		format;		/* Format identifier */
  SingleSubstFormat1	format1[];
  SingleSubstFormat2	format2[];
134
  } u;
B
Behdad Esfahbod 已提交
135
};
B
Behdad Esfahbod 已提交
136
ASSERT_SIZE (SingleSubst, 2);
137

B
Behdad Esfahbod 已提交
138 139

struct Sequence {
140 141 142 143 144 145 146

  friend struct MultipleSubstFormat1;

  private:

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

B
Behdad Esfahbod 已提交
147
    unsigned int count = substitute.len;
148
    for (unsigned int n = 0; n < count; n++)
149 150
      _hb_ot_layout_set_glyph_property (layout, substitute[n], property);
  }
B
Behdad Esfahbod 已提交
151

152
  inline bool substitute_sequence (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
153

B
Behdad Esfahbod 已提交
154
    if (HB_UNLIKELY (!substitute.len))
B
Behdad Esfahbod 已提交
155 156 157
      return false;

    _hb_buffer_add_output_glyph_ids (buffer, 1,
B
Behdad Esfahbod 已提交
158
				     substitute.len, substitute.array,
B
Behdad Esfahbod 已提交
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
				     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 已提交
174
  private:
B
Behdad Esfahbod 已提交
175 176
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
B
Behdad Esfahbod 已提交
177
};
178
ASSERT_SIZE (Sequence, 2);
B
Behdad Esfahbod 已提交
179

180 181 182 183 184 185
struct MultipleSubstFormat1 {

  friend struct MultipleSubst;

  private:

186
  inline bool substitute (LOOKUP_ARGS_DEF) const {
187

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

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

struct MultipleSubst {

205 206 207 208
  friend struct SubstLookupSubTable;

  private:

209
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
210 211
    switch (u.format) {
    case 1: return u.format1->substitute (LOOKUP_ARGS);
212 213 214 215 216 217
    default:return false;
    }
  }

  private:
  union {
B
Behdad Esfahbod 已提交
218 219
  USHORT		format;		/* Format identifier */
  MultipleSubstFormat1	format1[];
220 221
  } u;
};
B
Behdad Esfahbod 已提交
222
ASSERT_SIZE (MultipleSubst, 2);
223

B
Behdad Esfahbod 已提交
224

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

229
struct AlternateSubstFormat1 {
230 231 232 233 234

  friend struct AlternateSubst;

  private:

235
  inline bool substitute (LOOKUP_ARGS_DEF) const {
236

237
    hb_codepoint_t glyph_id = IN_CURGLYPH ();
238

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

B
Behdad Esfahbod 已提交
242
    if (HB_UNLIKELY (!alt_set.len))
243 244 245 246 247 248 249 250 251 252 253
      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 已提交
254
    if (HB_UNLIKELY (alt_index >= alt_set.len))
255 256 257 258
      return false;

    glyph_id = alt_set[alt_index];

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

    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 已提交
269 270

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

281 282 283 284 285 286
struct AlternateSubst {

  friend struct SubstLookupSubTable;

  private:

287
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
288 289
    switch (u.format) {
    case 1: return u.format1->substitute (LOOKUP_ARGS);
290 291 292 293 294 295
    default:return false;
    }
  }

  private:
  union {
B
Behdad Esfahbod 已提交
296 297
  USHORT		format;		/* Format identifier */
  AlternateSubstFormat1	format1[];
298 299
  } u;
};
B
Behdad Esfahbod 已提交
300
ASSERT_SIZE (AlternateSubst, 2);
301

302 303

struct Ligature {
304 305 306 307 308 309

  friend struct LigatureSet;

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

B
Behdad Esfahbod 已提交
310
  inline bool substitute_ligature (LOOKUP_ARGS_DEF, bool is_mark) const {
311 312 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

    unsigned int i, j;
    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. */

B
Behdad Esfahbod 已提交
359
      for ( i = 1; i < count; i++ )
360 361
      {
	while (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM(), lookup_flag, &property))
B
Behdad Esfahbod 已提交
362
	  _hb_buffer_add_output_glyph (buffer, IN_CURGLYPH(), i - 1, lig_id);
363 364 365 366 367 368 369 370 371 372 373

	(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;
  }
374 375 376 377 378 379 380 381

  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 */
};
382
ASSERT_SIZE (Ligature, 4);
B
Behdad Esfahbod 已提交
383 384

struct LigatureSet {
385 386 387 388 389

  friend struct LigatureSubstFormat1;

  private:

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

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

    return false;
  }
B
Behdad Esfahbod 已提交
401 402

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

409
struct LigatureSubstFormat1 {
410 411 412 413 414

  friend struct LigatureSubst;

  private:

415
  inline bool substitute (LOOKUP_ARGS_DEF) const {
416 417 418 419 420 421

    hb_codepoint_t glyph_id = IN_CURGLYPH ();

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

B
Behdad Esfahbod 已提交
422 423
    unsigned int index = (this+coverage) (glyph_id);
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
424
    return lig_set.substitute_ligature (LOOKUP_ARGS, first_is_mark);
425
  }
B
Behdad Esfahbod 已提交
426 427

  private:
B
Behdad Esfahbod 已提交
428
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
429 430
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
431
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
432 433 434
  OffsetArrayOf<LigatureSet>\
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
B
Behdad Esfahbod 已提交
435
};
436 437
ASSERT_SIZE (LigatureSubstFormat1, 6);

438 439 440 441 442 443
struct LigatureSubst {

  friend struct SubstLookupSubTable;

  private:

444
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
445 446
    switch (u.format) {
    case 1: return u.format1->substitute (LOOKUP_ARGS);
447 448 449 450 451 452
    default:return false;
    }
  }

  private:
  union {
B
Behdad Esfahbod 已提交
453 454
  USHORT		format;		/* Format identifier */
  LigatureSubstFormat1	format1[];
455 456
  } u;
};
B
Behdad Esfahbod 已提交
457
ASSERT_SIZE (LigatureSubst, 2);
458

B
Behdad Esfahbod 已提交
459

460

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

463
struct ContextSubst : Context {
B
Behdad Esfahbod 已提交
464

465
  inline bool substitute (LOOKUP_ARGS_DEF) const {
466
    return this->apply (LOOKUP_ARGS, substitute_lookup);
467 468
  }
};
B
Behdad Esfahbod 已提交
469
ASSERT_SIZE (ContextSubst, 2);
470 471


B
Behdad Esfahbod 已提交
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491
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) */
492 493
  USHORT	substCount;		/* Number of LookupRecords */
  LookupRecord	substLookupRecord[];	/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
494 495
					 * design order) */
};
496
ASSERT_SIZE (ChainSubRule, 8);
B
Behdad Esfahbod 已提交
497

B
Behdad Esfahbod 已提交
498
struct ChainSubRuleSet {
B
Behdad Esfahbod 已提交
499 500 501
  /* TODO */

  private:
B
Behdad Esfahbod 已提交
502 503
  USHORT	chainSubRuleCount;	/* Number of ChainSubRule tables */
  Offset	chainSubRule[];		/* Array of offsets to ChainSubRule
B
Behdad Esfahbod 已提交
504
					 * tables--from beginning of
B
Behdad Esfahbod 已提交
505 506
					 * ChainSubRuleSet table--ordered
					 * by preference */
B
Behdad Esfahbod 已提交
507
};
508
ASSERT_SIZE (ChainSubRuleSet, 2);
B
Behdad Esfahbod 已提交
509

B
Behdad Esfahbod 已提交
510
struct ChainContextSubstFormat1 {
B
Behdad Esfahbod 已提交
511
  /* TODO */
512
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
513 514
    return false;
  }
B
Behdad Esfahbod 已提交
515 516

  private:
B
Behdad Esfahbod 已提交
517
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
518 519 520 521 522 523
  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 已提交
524
					 * tables--from beginning of
B
Behdad Esfahbod 已提交
525 526
					 * Substitution table--ordered by
					 * Coverage Index */
B
Behdad Esfahbod 已提交
527
};
B
Behdad Esfahbod 已提交
528
ASSERT_SIZE (ChainContextSubstFormat1, 6);
B
Behdad Esfahbod 已提交
529 530 531 532 533 534 535 536 537

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 已提交
538
  USHORT	backtrack[];		/* Array of backtracking classes (to be
B
Behdad Esfahbod 已提交
539 540 541 542 543 544 545 546 547 548
					 * 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 已提交
549
  USHORT	lookAhead[];		/* Array of lookahead classes (to be
B
Behdad Esfahbod 已提交
550
					 * matched after the  input sequence) */
551 552
  USHORT	substCount;		/* Number of LookupRecords */
  LookupRecord	substLookupRecord[];	/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
553 554
					 * design order) */
};
555
ASSERT_SIZE (ChainSubClassRule, 8);
B
Behdad Esfahbod 已提交
556

B
Behdad Esfahbod 已提交
557 558 559 560 561 562 563 564 565 566 567
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 */
};
568
ASSERT_SIZE (ChainSubClassSet, 2);
B
Behdad Esfahbod 已提交
569 570 571

struct ChainContextSubstFormat2 {
  /* TODO */
572
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
573 574
    return false;
  }
B
Behdad Esfahbod 已提交
575 576

  private:
B
Behdad Esfahbod 已提交
577
  USHORT	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
  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 已提交
600 601
struct ChainContextSubstFormat3 {
  /* TODO */
602
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
603 604
    return false;
  }
B
Behdad Esfahbod 已提交
605 606

  private:
B
Behdad Esfahbod 已提交
607
  USHORT	format;			/* Format identifier--format = 3 */
B
Behdad Esfahbod 已提交
608 609 610 611 612 613 614 615 616 617 618 619 620 621
  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 */
622 623
  USHORT	substCount;		/* Number of LookupRecords */
  LookupRecord	substLookupRecord[];	/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
624 625 626 627
					 * design order */
};
ASSERT_SIZE (ChainContextSubstFormat3, 10);

B
Behdad Esfahbod 已提交
628 629 630 631 632 633
struct ChainContextSubst {

  friend struct SubstLookupSubTable;

  private:

634
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
635 636 637 638
    switch (u.format) {
    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 已提交
639 640 641 642 643 644
    default:return false;
    }
  }

  private:
  union {
B
Behdad Esfahbod 已提交
645 646 647 648
  USHORT			format;	/* Format identifier */
  ChainContextSubstFormat1	format1[];
  ChainContextSubstFormat2	format2[];
  ChainContextSubstFormat3	format3[];
B
Behdad Esfahbod 已提交
649 650
  } u;
};
B
Behdad Esfahbod 已提交
651
ASSERT_SIZE (ChainContextSubst, 2);
B
Behdad Esfahbod 已提交
652

653

B
Behdad Esfahbod 已提交
654
struct ExtensionSubstFormat1 {
655 656 657 658 659

  friend struct ExtensionSubst;

  private:
  inline unsigned int get_type (void) const { return extensionLookupType; }
B
Behdad Esfahbod 已提交
660
  inline unsigned int get_offset (void) const { return (extensionOffset[0] << 16) + extensionOffset[1]; }
661
  inline bool substitute (LOOKUP_ARGS_DEF) const;
B
Behdad Esfahbod 已提交
662 663

  private:
B
Behdad Esfahbod 已提交
664
  USHORT	format;			/* Format identifier. Set to 1. */
B
Behdad Esfahbod 已提交
665 666 667
  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
					 * by ExtensionOffset (i.e. the
					 * extension subtable). */
B
Behdad Esfahbod 已提交
668 669 670 671
  USHORT	extensionOffset[2];	/* Offset to the extension subtable,
					 * of lookup type subtable.
					 * Defined as two shorts to avoid
					 * alignment requirements. */
B
Behdad Esfahbod 已提交
672 673 674
};
ASSERT_SIZE (ExtensionSubstFormat1, 8);

675 676 677 678 679 680 681 682
struct ExtensionSubst {

  friend struct SubstLookup;
  friend struct SubstLookupSubTable;

  private:

  inline unsigned int get_type (void) const {
B
Behdad Esfahbod 已提交
683 684
    switch (u.format) {
    case 1: return u.format1->get_type ();
685 686 687 688
    default:return 0;
    }
  }

689
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
690 691
    switch (u.format) {
    case 1: return u.format1->substitute (LOOKUP_ARGS);
692 693 694 695 696 697
    default:return false;
    }
  }

  private:
  union {
B
Behdad Esfahbod 已提交
698 699
  USHORT		format;		/* Format identifier */
  ExtensionSubstFormat1	format1[];
700 701
  } u;
};
B
Behdad Esfahbod 已提交
702
ASSERT_SIZE (ExtensionSubst, 2);
703 704 705



B
Behdad Esfahbod 已提交
706 707 708 709
struct ReverseChainSingleSubstFormat1 {
  /* TODO */

  private:
B
Behdad Esfahbod 已提交
710
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
  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 已提交
730 731 732 733
/*
 * SubstLookup
 */

734 735 736
enum {
  GSUB_Single				= 1,
  GSUB_Multiple				= 2,
737
  GSUB_Alternate			= 3,
738 739 740
  GSUB_Ligature				= 4,
  GSUB_Context				= 5,
  GSUB_ChainingContext			= 6,
741 742
  GSUB_Extension			= 7,
  GSUB_ReverseChainingContextSingle	= 8,
743 744
};

B
Behdad Esfahbod 已提交
745 746 747 748
struct SubstLookupSubTable {

  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
749
  inline bool substitute (LOOKUP_ARGS_DEF,
750
			  unsigned int lookup_type) const {
751

752
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
753 754 755 756 757
    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);
758
    /*
B
Behdad Esfahbod 已提交
759
    case GSUB_ChainingContext:			return u.chainingContext->substitute (LOOKUP_ARGS);
760
    */
B
Behdad Esfahbod 已提交
761
    case GSUB_Extension:			return u.extension->substitute (LOOKUP_ARGS);
762
			/*
B
Behdad Esfahbod 已提交
763
    case GSUB_ReverseChainingContextSingle:	return u.reverseChainingContextSingle->substitute (LOOKUP_ARGS);
764 765 766
    */
    default:return false;
    }
B
Behdad Esfahbod 已提交
767 768 769 770
  }

  private:
  union {
B
Behdad Esfahbod 已提交
771 772 773 774 775 776
  USHORT				format;
  SingleSubst				single[];
  MultipleSubst				multiple[];
  AlternateSubst			alternate[];
  LigatureSubst				ligature[];
  ContextSubst				context[];
777
  /*
B
Behdad Esfahbod 已提交
778
  ChainingContextSubst			chainingContext[];
779
  */
B
Behdad Esfahbod 已提交
780
  ExtensionSubst			extension[];
781
  /*
B
Behdad Esfahbod 已提交
782
  ReverseChainingContextSingleSubst	reverseChainingContextSingle[];
783
  */
B
Behdad Esfahbod 已提交
784 785
  } u;
};
B
Behdad Esfahbod 已提交
786
ASSERT_SIZE (SubstLookupSubTable, 2);
B
Behdad Esfahbod 已提交
787

788

B
Behdad Esfahbod 已提交
789 790 791 792 793 794 795
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.
796
   * Never returns Extension */
B
Behdad Esfahbod 已提交
797 798 799
  inline unsigned int get_effective_type (void) const {
    unsigned int type = get_type ();

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

    return type;
  }

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

817 818 819 820 821
  inline bool substitute_subtables (hb_ot_layout_t *layout,
				    hb_buffer_t    *buffer,
				    unsigned int    context_length,
				    unsigned int    nesting_level_left,
				    unsigned int    property) const {
B
Behdad Esfahbod 已提交
822
    unsigned int lookup_type = get_type ();
B
Behdad Esfahbod 已提交
823
    unsigned int lookup_flag = get_flag ();
B
Behdad Esfahbod 已提交
824 825

    for (unsigned int i = 0; i < get_subtable_count (); i++)
B
Behdad Esfahbod 已提交
826
      if (get_subtable (i).substitute (LOOKUP_ARGS,
827
				       lookup_type))
B
Behdad Esfahbod 已提交
828
	return true;
B
Behdad Esfahbod 已提交
829

B
Behdad Esfahbod 已提交
830 831
    return false;
  }
832

833 834 835 836 837 838 839 840 841 842 843 844
  inline bool substitute_once (hb_ot_layout_t *layout,
			       hb_buffer_t    *buffer) const {

    unsigned int lookup_flag = get_flag ();

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

    return substitute_subtables (layout, buffer, NO_CONTEXT, MAX_NESTING_LEVEL, property);
  }

845 846 847
  bool substitute_string (hb_ot_layout_t *layout,
			  hb_buffer_t    *buffer,
			  hb_ot_layout_feature_mask_t mask) const {
848 849 850

    bool ret = false;

B
Behdad Esfahbod 已提交
851 852 853
    if (HB_UNLIKELY (!buffer->in_length))
      return false;

854
    if (HB_LIKELY (!is_reverse ())) {
855 856 857 858 859 860 861

	/* 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) &&
862
	      substitute_once (layout, buffer))
863 864
	    ret = true;
	  else
B
Behdad Esfahbod 已提交
865
	    _hb_buffer_next_glyph (buffer);
866 867 868 869 870 871 872 873 874 875 876 877

	}
	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) &&
878
	      substitute_once (layout, buffer))
879 880 881 882
	    ret = true;
	  else
	    buffer->in_pos--;

883
	} while ((int) buffer->in_pos >= 0);
884 885 886 887
    }

    return ret;
  }
B
Behdad Esfahbod 已提交
888
};
B
Behdad Esfahbod 已提交
889
ASSERT_SIZE (SubstLookup, 6);
B
Behdad Esfahbod 已提交
890

891

B
Minor  
Behdad Esfahbod 已提交
892 893 894 895 896 897 898 899 900
/*
 * 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 已提交
901 902 903 904 905

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

906 907 908 909 910 911
  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 已提交
912

B
Minor  
Behdad Esfahbod 已提交
913
};
B
Behdad Esfahbod 已提交
914
ASSERT_SIZE (GSUB, 10);
915 916 917 918


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

919
inline bool ExtensionSubstFormat1::substitute (LOOKUP_ARGS_DEF) const {
920 921
  /* XXX either check in sanitize or here that the lookuptype is not 7 again,
   * or we can loop indefinitely. */
B
Behdad Esfahbod 已提交
922
  return (*(SubstLookupSubTable *)(((char *) this) + get_offset ())).substitute (LOOKUP_ARGS,
923 924 925
										   get_type ());
}

926
static inline bool substitute_lookup (LOOKUP_ARGS_DEF, unsigned int lookup_index) {
927
  const GSUB &gsub = *(layout->gsub);
928
  const SubstLookup &l = gsub.get_lookup (lookup_index);
929

930 931 932 933 934 935 936
  if (HB_UNLIKELY (nesting_level_left == 0))
    return false;
  nesting_level_left--;

  if (HB_UNLIKELY (context_length < 1))
    return false;

937
  return l.substitute_subtables (layout, buffer, context_length, nesting_level_left, property);
938 939 940
}


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