hb-ot-layout-gsub-private.h 20.2 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 );

42

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

  friend struct SingleSubst;

  private:
B
Behdad Esfahbod 已提交
48

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

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

    glyph_id += deltaGlyphID;

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

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

struct SingleSubstFormat2 {
71 72 73 74 75 76 77

  friend struct SingleSubst;

  private:

  inline bool single_substitute (hb_codepoint_t &glyph_id) const {

B
Behdad Esfahbod 已提交
78
    unsigned int index = (this+coverage) (glyph_id);
79 80
    if (G_LIKELY (index == NOT_COVERED))
      return false;
81

82
    if (G_UNLIKELY (index >= substitute.len))
83 84 85 86 87
      return false;

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

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

100 101 102 103
struct SingleSubst {

  friend struct SubstLookupSubTable;

104 105
  private:

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

114
  inline bool substitute (LOOKUP_ARGS_DEF) const {
115

116
    hb_codepoint_t glyph_id = IN_CURGLYPH ();
117

B
Behdad Esfahbod 已提交
118 119
    if (!single_substitute (glyph_id))
      return false;
120

B
Behdad Esfahbod 已提交
121
    _hb_buffer_replace_glyph (buffer, glyph_id);
122 123 124 125 126 127 128 129 130 131 132 133

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

B
Behdad Esfahbod 已提交
141 142

struct Sequence {
143 144 145 146 147 148 149

  friend struct MultipleSubstFormat1;

  private:

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

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

155
  inline bool substitute_sequence (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
156

B
Behdad Esfahbod 已提交
157
    if (HB_UNLIKELY (!substitute.len))
B
Behdad Esfahbod 已提交
158 159 160
      return false;

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

183 184 185 186 187 188
struct MultipleSubstFormat1 {

  friend struct MultipleSubst;

  private:

189
  inline bool substitute (LOOKUP_ARGS_DEF) const {
190

B
Behdad Esfahbod 已提交
191
    unsigned int index = (this+coverage) (IN_CURGLYPH ());
192 193 194
    if (G_LIKELY (index == NOT_COVERED))
      return false;

195
    return (this+sequence[index]).substitute_sequence (LOOKUP_ARGS);
196
  }
B
Behdad Esfahbod 已提交
197 198

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

struct MultipleSubst {

211 212 213 214
  friend struct SubstLookupSubTable;

  private:

215
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
216 217
    switch (u.format) {
    case 1: return u.format1->substitute (LOOKUP_ARGS);
218 219 220 221 222 223
    default:return false;
    }
  }

  private:
  union {
B
Behdad Esfahbod 已提交
224 225
  USHORT		format;		/* Format identifier */
  MultipleSubstFormat1	format1[];
226 227
  } u;
};
B
Behdad Esfahbod 已提交
228
ASSERT_SIZE (MultipleSubst, 2);
229

B
Behdad Esfahbod 已提交
230

B
Behdad Esfahbod 已提交
231
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
232
					 * arbitrary order */
233
ASSERT_SIZE (AlternateSet, 2);
B
Behdad Esfahbod 已提交
234

235
struct AlternateSubstFormat1 {
236 237 238 239 240

  friend struct AlternateSubst;

  private:

241
  inline bool substitute (LOOKUP_ARGS_DEF) const {
242

243
    hb_codepoint_t glyph_id = IN_CURGLYPH ();
244

B
Behdad Esfahbod 已提交
245
    unsigned int index = (this+coverage) (glyph_id);
246 247 248
    if (G_LIKELY (index == NOT_COVERED))
      return false;

B
Behdad Esfahbod 已提交
249
    const AlternateSet &alt_set = this+alternateSet[index];
250

B
Behdad Esfahbod 已提交
251
    if (HB_UNLIKELY (!alt_set.len))
252 253 254 255 256 257 258 259 260 261 262
      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 已提交
263
    if (HB_UNLIKELY (alt_index >= alt_set.len))
264 265 266 267
      return false;

    glyph_id = alt_set[alt_index];

B
Behdad Esfahbod 已提交
268
    _hb_buffer_replace_glyph (buffer, glyph_id);
269 270 271 272 273 274 275 276 277

    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 已提交
278 279

  private:
B
Behdad Esfahbod 已提交
280
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
281 282
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
283
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
284 285 286
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
B
Behdad Esfahbod 已提交
287
};
288 289
ASSERT_SIZE (AlternateSubstFormat1, 6);

290 291 292 293 294 295
struct AlternateSubst {

  friend struct SubstLookupSubTable;

  private:

296
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
297 298
    switch (u.format) {
    case 1: return u.format1->substitute (LOOKUP_ARGS);
299 300 301 302 303 304
    default:return false;
    }
  }

  private:
  union {
B
Behdad Esfahbod 已提交
305 306
  USHORT		format;		/* Format identifier */
  AlternateSubstFormat1	format1[];
307 308
  } u;
};
B
Behdad Esfahbod 已提交
309
ASSERT_SIZE (AlternateSubst, 2);
310

311 312

struct Ligature {
313 314 315 316

  friend struct LigatureSet;

  private:
B
Behdad Esfahbod 已提交
317
  inline bool substitute_ligature (LOOKUP_ARGS_DEF, bool is_mark) const {
318 319

    unsigned int i, j;
B
Behdad Esfahbod 已提交
320
    unsigned int count = component.len;
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336

    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;

B
Behdad Esfahbod 已提交
337
      if (HB_LIKELY (IN_GLYPH(j) != component[i]))
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
        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 已提交
366
      for ( i = 1; i < count; i++ )
367 368
      {
	while (!_hb_ot_layout_check_glyph_property (layout, IN_CURITEM(), lookup_flag, &property))
B
Behdad Esfahbod 已提交
369
	  _hb_buffer_add_output_glyph (buffer, IN_CURGLYPH(), i - 1, lig_id);
370 371 372 373 374 375 376 377 378 379 380

	(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;
  }
381 382 383

  private:
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
384 385
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
386 387 388
					 * with the second  component--ordered
					 * in writing direction */
};
389
ASSERT_SIZE (Ligature, 4);
B
Behdad Esfahbod 已提交
390 391

struct LigatureSet {
392 393 394 395 396

  friend struct LigatureSubstFormat1;

  private:

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

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

    return false;
  }
B
Behdad Esfahbod 已提交
408 409

  private:
B
Behdad Esfahbod 已提交
410 411 412
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
B
Behdad Esfahbod 已提交
413
};
414
ASSERT_SIZE (LigatureSet, 2);
B
Behdad Esfahbod 已提交
415

416
struct LigatureSubstFormat1 {
417 418 419 420 421

  friend struct LigatureSubst;

  private:

422
  inline bool substitute (LOOKUP_ARGS_DEF) const {
423 424 425 426 427 428

    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
    unsigned int index = (this+coverage) (glyph_id);
430 431 432
    if (G_LIKELY (index == NOT_COVERED))
      return false;

B
Behdad Esfahbod 已提交
433
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
434
    return lig_set.substitute_ligature (LOOKUP_ARGS, first_is_mark);
435
  }
B
Behdad Esfahbod 已提交
436 437

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

448 449 450 451 452 453
struct LigatureSubst {

  friend struct SubstLookupSubTable;

  private:

454
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
455 456
    switch (u.format) {
    case 1: return u.format1->substitute (LOOKUP_ARGS);
457 458 459 460 461 462
    default:return false;
    }
  }

  private:
  union {
B
Behdad Esfahbod 已提交
463 464
  USHORT		format;		/* Format identifier */
  LigatureSubstFormat1	format1[];
465 466
  } u;
};
B
Behdad Esfahbod 已提交
467
ASSERT_SIZE (LigatureSubst, 2);
468

B
Behdad Esfahbod 已提交
469

470

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

473

474
struct ContextSubst : Context {
B
Behdad Esfahbod 已提交
475

476
  inline bool substitute (LOOKUP_ARGS_DEF) const {
477
    return this->apply (LOOKUP_ARGS, substitute_lookup);
478 479
  }
};
B
Behdad Esfahbod 已提交
480
ASSERT_SIZE (ContextSubst, 2);
481 482


483
struct ChainContextSubst : ChainContext {
B
Behdad Esfahbod 已提交
484

485
  inline bool substitute (LOOKUP_ARGS_DEF) const {
486
    return this->apply (LOOKUP_ARGS, substitute_lookup);
B
Behdad Esfahbod 已提交
487 488
  }
};
B
Behdad Esfahbod 已提交
489
ASSERT_SIZE (ChainContextSubst, 2);
B
Behdad Esfahbod 已提交
490

491

B
Behdad Esfahbod 已提交
492
struct ExtensionSubstFormat1 {
493 494 495 496 497

  friend struct ExtensionSubst;

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

  private:
B
Behdad Esfahbod 已提交
502
  USHORT	format;			/* Format identifier. Set to 1. */
B
Behdad Esfahbod 已提交
503 504 505
  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
					 * by ExtensionOffset (i.e. the
					 * extension subtable). */
B
Behdad Esfahbod 已提交
506 507 508 509
  USHORT	extensionOffset[2];	/* Offset to the extension subtable,
					 * of lookup type subtable.
					 * Defined as two shorts to avoid
					 * alignment requirements. */
B
Behdad Esfahbod 已提交
510 511 512
};
ASSERT_SIZE (ExtensionSubstFormat1, 8);

513 514 515 516 517 518 519 520
struct ExtensionSubst {

  friend struct SubstLookup;
  friend struct SubstLookupSubTable;

  private:

  inline unsigned int get_type (void) const {
B
Behdad Esfahbod 已提交
521 522
    switch (u.format) {
    case 1: return u.format1->get_type ();
523 524 525 526
    default:return 0;
    }
  }

527
  inline bool substitute (LOOKUP_ARGS_DEF) const {
B
Behdad Esfahbod 已提交
528 529
    switch (u.format) {
    case 1: return u.format1->substitute (LOOKUP_ARGS);
530 531 532 533 534 535
    default:return false;
    }
  }

  private:
  union {
B
Behdad Esfahbod 已提交
536 537
  USHORT		format;		/* Format identifier */
  ExtensionSubstFormat1	format1[];
538 539
  } u;
};
B
Behdad Esfahbod 已提交
540
ASSERT_SIZE (ExtensionSubst, 2);
541 542


B
Behdad Esfahbod 已提交
543 544
struct ReverseChainSingleSubstFormat1 {
  /* TODO */
545 546 547
  inline bool substitute (LOOKUP_ARGS_DEF) const {
    return false;
  }
B
Behdad Esfahbod 已提交
548 549

  private:
B
Behdad Esfahbod 已提交
550
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
551 552 553 554 555 556 557 558 559 560 561 562 563 564
  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 */
565
  GlyphID	substituteGlyphs[];	/* Array of substitute
B
Behdad Esfahbod 已提交
566 567 568 569
					 * GlyphIDs--ordered by Coverage  Index */
};
ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);

570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
struct ReverseChainSingleSubst {

  friend struct SubstLookupSubTable;

  private:

  inline bool substitute (LOOKUP_ARGS_DEF) const {
    switch (u.format) {
    case 1: return u.format1->substitute (LOOKUP_ARGS);
    default:return false;
    }
  }

  private:
  union {
  USHORT				format;		/* Format identifier */
  ReverseChainSingleSubstFormat1	format1[];
  } u;
};
ASSERT_SIZE (ReverseChainSingleSubst, 2);



B
Behdad Esfahbod 已提交
593 594 595 596
/*
 * SubstLookup
 */

597
enum {
598 599 600 601 602 603 604 605
  GSUB_Single			= 1,
  GSUB_Multiple			= 2,
  GSUB_Alternate		= 3,
  GSUB_Ligature			= 4,
  GSUB_Context			= 5,
  GSUB_ChainContext		= 6,
  GSUB_Extension		= 7,
  GSUB_ReverseChainSingle	= 8,
606 607
};

B
Behdad Esfahbod 已提交
608 609 610 611
struct SubstLookupSubTable {

  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
612
  inline bool substitute (LOOKUP_ARGS_DEF,
613
			  unsigned int lookup_type) const {
614

615
    switch (lookup_type) {
616 617 618 619 620 621 622 623
    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);
    case GSUB_ChainContext:		return u.chainingContext->substitute (LOOKUP_ARGS);
    case GSUB_Extension:		return u.extension->substitute (LOOKUP_ARGS);
    case GSUB_ReverseChainSingle:	return u.reverseChainContextSingle->substitute (LOOKUP_ARGS);
624 625
    default:return false;
    }
B
Behdad Esfahbod 已提交
626 627 628 629
  }

  private:
  union {
630 631 632 633 634 635 636 637 638
  USHORT			format;
  SingleSubst			single[];
  MultipleSubst			multiple[];
  AlternateSubst		alternate[];
  LigatureSubst			ligature[];
  ContextSubst			context[];
  ChainContextSubst		chainingContext[];
  ExtensionSubst		extension[];
  ReverseChainSingleSubst	reverseChainContextSingle[];
B
Behdad Esfahbod 已提交
639 640
  } u;
};
B
Behdad Esfahbod 已提交
641
ASSERT_SIZE (SubstLookupSubTable, 2);
B
Behdad Esfahbod 已提交
642

643

B
Behdad Esfahbod 已提交
644 645 646 647 648 649 650
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.
651
   * Never returns Extension */
B
Behdad Esfahbod 已提交
652 653 654
  inline unsigned int get_effective_type (void) const {
    unsigned int type = get_type ();

655
    if (HB_UNLIKELY (type == GSUB_Extension)) {
B
Behdad Esfahbod 已提交
656 657
      /* Return lookup type of first extension subtable.
       * The spec says all of them should have the same type.
658
       * XXX check for that in sanitize() */
B
Behdad Esfahbod 已提交
659
      type = get_subtable(0).u.extension->get_type ();
B
Behdad Esfahbod 已提交
660 661 662 663 664 665 666
    }

    return type;
  }

  inline bool is_reverse (void) const {
    switch (get_effective_type ()) {
667 668
    case GSUB_ReverseChainSingle:	return true;
    default:				return false;
B
Behdad Esfahbod 已提交
669 670 671
    }
  }

672 673 674 675 676
  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 已提交
677
    unsigned int lookup_type = get_type ();
B
Behdad Esfahbod 已提交
678
    unsigned int lookup_flag = get_flag ();
B
Behdad Esfahbod 已提交
679 680

    for (unsigned int i = 0; i < get_subtable_count (); i++)
B
Behdad Esfahbod 已提交
681
      if (get_subtable (i).substitute (LOOKUP_ARGS,
682
				       lookup_type))
B
Behdad Esfahbod 已提交
683
	return true;
B
Behdad Esfahbod 已提交
684

B
Behdad Esfahbod 已提交
685 686
    return false;
  }
687

688 689 690 691 692 693 694 695 696 697 698 699
  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);
  }

700 701 702
  bool substitute_string (hb_ot_layout_t *layout,
			  hb_buffer_t    *buffer,
			  hb_ot_layout_feature_mask_t mask) const {
703 704 705

    bool ret = false;

B
Behdad Esfahbod 已提交
706 707 708
    if (HB_UNLIKELY (!buffer->in_length))
      return false;

709
    if (HB_LIKELY (!is_reverse ())) {
710 711 712 713 714 715 716

	/* 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) &&
717
	      substitute_once (layout, buffer))
718 719
	    ret = true;
	  else
B
Behdad Esfahbod 已提交
720
	    _hb_buffer_next_glyph (buffer);
721 722 723 724 725 726 727 728 729 730 731 732

	}
	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) &&
733
	      substitute_once (layout, buffer))
734 735 736 737
	    ret = true;
	  else
	    buffer->in_pos--;

738
	} while ((int) buffer->in_pos >= 0);
739 740 741 742
    }

    return ret;
  }
B
Behdad Esfahbod 已提交
743
};
B
Behdad Esfahbod 已提交
744
ASSERT_SIZE (SubstLookup, 6);
B
Behdad Esfahbod 已提交
745

746

B
Minor  
Behdad Esfahbod 已提交
747 748 749 750 751 752 753 754 755
/*
 * 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 已提交
756 757 758 759 760

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

761 762 763 764 765 766
  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 已提交
767

B
Minor  
Behdad Esfahbod 已提交
768
};
B
Behdad Esfahbod 已提交
769
ASSERT_SIZE (GSUB, 10);
770 771


B
Behdad Esfahbod 已提交
772
/* Out-of-class implementation for methods recursing */
773

774
inline bool ExtensionSubstFormat1::substitute (LOOKUP_ARGS_DEF) const {
775 776 777 778 779 780
  unsigned int lookup_type = get_type ();

  /* TODO: belongs to sanitize() */
  if (HB_UNLIKELY (lookup_type == GSUB_ReverseChainSingle))
    return false;

B
Behdad Esfahbod 已提交
781
  return (*(SubstLookupSubTable *)(((char *) this) + get_offset ())).substitute (LOOKUP_ARGS,
782
										 lookup_type);
783 784
}

785
static inline bool substitute_lookup (LOOKUP_ARGS_DEF, unsigned int lookup_index) {
786
  const GSUB &gsub = *(layout->gsub);
787
  const SubstLookup &l = gsub.get_lookup (lookup_index);
788

789 790 791 792 793 794 795
  if (HB_UNLIKELY (nesting_level_left == 0))
    return false;
  nesting_level_left--;

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

796
  return l.substitute_subtables (layout, buffer, context_length, nesting_level_left, property);
797 798 799
}


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