hb-aat-layout-common.hh 24.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * Copyright © 2017  Google, Inc.
 *
 *  This is part of HarfBuzz, a text shaping 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.
 *
 * Google Author(s): Behdad Esfahbod
 */

27 28
#ifndef HB_AAT_LAYOUT_COMMON_HH
#define HB_AAT_LAYOUT_COMMON_HH
29

30
#include "hb-aat-layout.hh"
31
#include "hb-open-type.hh"
32 33 34 35 36 37 38


namespace AAT {

using namespace OT;


B
Behdad Esfahbod 已提交
39 40 41 42 43 44 45 46 47 48 49 50
/*
 * Lookup Table
 */

template <typename T> struct Lookup;

template <typename T>
struct LookupFormat0
{
  friend struct Lookup<T>;

  private:
51
  const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
B
Behdad Esfahbod 已提交
52
  {
53 54
    if (unlikely (glyph_id >= num_glyphs)) return nullptr;
    return &arrayZ[glyph_id];
B
Behdad Esfahbod 已提交
55 56
  }

57
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
58 59
  {
    TRACE_SANITIZE (this);
60
    return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
B
Behdad Esfahbod 已提交
61
  }
62
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
63 64 65 66
  {
    TRACE_SANITIZE (this);
    return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base));
  }
B
Behdad Esfahbod 已提交
67 68

  protected:
B
Behdad Esfahbod 已提交
69
  HBUINT16	format;		/* Format identifier--format = 0 */
B
Behdad Esfahbod 已提交
70 71 72
  UnsizedArrayOf<T>
		arrayZ;		/* Array of lookup values, indexed by glyph index. */
  public:
73
  DEFINE_SIZE_UNBOUNDED (2);
B
Behdad Esfahbod 已提交
74 75 76 77 78 79
};


template <typename T>
struct LookupSegmentSingle
{
80
  static constexpr unsigned TerminationWordCount = 2u;
81

82 83
  int cmp (hb_codepoint_t g) const
  { return g < first ? -1 : g <= last ? 0 : +1 ; }
B
Behdad Esfahbod 已提交
84

85
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
86 87 88 89
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && value.sanitize (c));
  }
90
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
91 92 93 94
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && value.sanitize (c, base));
  }
B
Behdad Esfahbod 已提交
95 96 97 98 99

  GlyphID	last;		/* Last GlyphID in this segment */
  GlyphID	first;		/* First GlyphID in this segment */
  T		value;		/* The lookup value (only one) */
  public:
100
  DEFINE_SIZE_STATIC (4 + T::static_size);
B
Behdad Esfahbod 已提交
101 102 103 104 105 106 107 108
};

template <typename T>
struct LookupFormat2
{
  friend struct Lookup<T>;

  private:
109
  const T* get_value (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
110 111
  {
    const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
112
    return v ? &v->value : nullptr;
B
Behdad Esfahbod 已提交
113 114
  }

115
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
116 117 118 119
  {
    TRACE_SANITIZE (this);
    return_trace (segments.sanitize (c));
  }
120
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
121 122 123 124
  {
    TRACE_SANITIZE (this);
    return_trace (segments.sanitize (c, base));
  }
B
Behdad Esfahbod 已提交
125 126

  protected:
B
Behdad Esfahbod 已提交
127
  HBUINT16	format;		/* Format identifier--format = 2 */
128
  VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
B
Behdad Esfahbod 已提交
129 130 131 132 133 134 135 136 137 138
		segments;	/* The actual segments. These must already be sorted,
				 * according to the first word in each one (the last
				 * glyph in each segment). */
  public:
  DEFINE_SIZE_ARRAY (8, segments);
};

template <typename T>
struct LookupSegmentArray
{
139
  static constexpr unsigned TerminationWordCount = 2u;
140

141
  const T* get_value (hb_codepoint_t glyph_id, const void *base) const
B
Behdad Esfahbod 已提交
142
  {
143
    return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
B
Behdad Esfahbod 已提交
144 145
  }

146 147
  int cmp (hb_codepoint_t g) const
  { return g < first ? -1 : g <= last ? 0 : +1; }
B
Behdad Esfahbod 已提交
148

149
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
B
Behdad Esfahbod 已提交
150 151 152 153 154 155
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  first <= last &&
		  valuesZ.sanitize (c, base, last - first + 1));
  }
156
  template <typename ...Ts>
B
Behdad Esfahbod 已提交
157
  bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
158 159 160 161
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  first <= last &&
162
		  valuesZ.sanitize (c, base, last - first + 1, hb_forward<Ts> (ds)...));
163
  }
B
Behdad Esfahbod 已提交
164 165 166

  GlyphID	last;		/* Last GlyphID in this segment */
  GlyphID	first;		/* First GlyphID in this segment */
167
  NNOffsetTo<UnsizedArrayOf<T>>
B
Behdad Esfahbod 已提交
168 169 170 171 172 173 174 175 176 177 178 179
		valuesZ;	/* A 16-bit offset from the start of
				 * the table to the data. */
  public:
  DEFINE_SIZE_STATIC (6);
};

template <typename T>
struct LookupFormat4
{
  friend struct Lookup<T>;

  private:
180
  const T* get_value (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
181 182
  {
    const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
183
    return v ? v->get_value (glyph_id, this) : nullptr;
B
Behdad Esfahbod 已提交
184 185
  }

186
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
187 188 189 190
  {
    TRACE_SANITIZE (this);
    return_trace (segments.sanitize (c, this));
  }
191
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
192 193 194 195
  {
    TRACE_SANITIZE (this);
    return_trace (segments.sanitize (c, this, base));
  }
B
Behdad Esfahbod 已提交
196 197

  protected:
198
  HBUINT16	format;		/* Format identifier--format = 4 */
199
  VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
B
Behdad Esfahbod 已提交
200 201 202 203 204 205 206 207 208 209
		segments;	/* The actual segments. These must already be sorted,
				 * according to the first word in each one (the last
				 * glyph in each segment). */
  public:
  DEFINE_SIZE_ARRAY (8, segments);
};

template <typename T>
struct LookupSingle
{
210
  static constexpr unsigned TerminationWordCount = 1u;
211

212
  int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }
B
Behdad Esfahbod 已提交
213

214
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
215 216 217 218
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && value.sanitize (c));
  }
219
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
220 221 222 223
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && value.sanitize (c, base));
  }
B
Behdad Esfahbod 已提交
224 225 226 227

  GlyphID	glyph;		/* Last GlyphID */
  T		value;		/* The lookup value (only one) */
  public:
228
  DEFINE_SIZE_STATIC (2 + T::static_size);
B
Behdad Esfahbod 已提交
229 230 231 232 233 234 235 236
};

template <typename T>
struct LookupFormat6
{
  friend struct Lookup<T>;

  private:
237
  const T* get_value (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
238 239
  {
    const LookupSingle<T> *v = entries.bsearch (glyph_id);
240
    return v ? &v->value : nullptr;
B
Behdad Esfahbod 已提交
241 242
  }

243
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
244 245 246 247
  {
    TRACE_SANITIZE (this);
    return_trace (entries.sanitize (c));
  }
248
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
249 250 251 252
  {
    TRACE_SANITIZE (this);
    return_trace (entries.sanitize (c, base));
  }
B
Behdad Esfahbod 已提交
253 254

  protected:
B
Behdad Esfahbod 已提交
255
  HBUINT16	format;		/* Format identifier--format = 6 */
256
  VarSizedBinSearchArrayOf<LookupSingle<T>>
B
Behdad Esfahbod 已提交
257 258 259 260 261 262 263 264 265 266 267
		entries;	/* The actual entries, sorted by glyph index. */
  public:
  DEFINE_SIZE_ARRAY (8, entries);
};

template <typename T>
struct LookupFormat8
{
  friend struct Lookup<T>;

  private:
268
  const T* get_value (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
269
  {
B
Behdad Esfahbod 已提交
270 271
    return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ?
	   &valueArrayZ[glyph_id - firstGlyph] : nullptr;
B
Behdad Esfahbod 已提交
272 273
  }

274
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
275 276 277 278
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
  }
279
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
280 281 282 283
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base));
  }
B
Behdad Esfahbod 已提交
284 285

  protected:
B
Behdad Esfahbod 已提交
286
  HBUINT16	format;		/* Format identifier--format = 8 */
B
Behdad Esfahbod 已提交
287
  GlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
B
Behdad Esfahbod 已提交
288
  HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
B
Behdad Esfahbod 已提交
289 290 291 292 293 294 295 296
				 * glyph minus the value of firstGlyph plus 1). */
  UnsizedArrayOf<T>
		valueArrayZ;	/* The lookup values (indexed by the glyph index
				 * minus the value of firstGlyph). */
  public:
  DEFINE_SIZE_ARRAY (6, valueArrayZ);
};

B
Behdad Esfahbod 已提交
297 298 299 300 301 302
template <typename T>
struct LookupFormat10
{
  friend struct Lookup<T>;

  private:
303
  const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317
  {
    if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
      return Null(T);

    const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];

    unsigned int v = 0;
    unsigned int count = valueSize;
    for (unsigned int i = 0; i < count; i++)
      v = (v << 8) | *p++;

    return v;
  }

318
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  valueSize <= 4 &&
		  valueArrayZ.sanitize (c, glyphCount * valueSize));
  }

  protected:
  HBUINT16	format;		/* Format identifier--format = 8 */
  HBUINT16	valueSize;	/* Byte size of each value. */
  GlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
  HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
				 * glyph minus the value of firstGlyph plus 1). */
  UnsizedArrayOf<HBUINT8>
		valueArrayZ;	/* The lookup values (indexed by the glyph index
				 * minus the value of firstGlyph). */
  public:
336
  DEFINE_SIZE_ARRAY (8, valueArrayZ);
B
Behdad Esfahbod 已提交
337 338
};

B
Behdad Esfahbod 已提交
339 340 341
template <typename T>
struct Lookup
{
342
  const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
B
Behdad Esfahbod 已提交
343 344 345 346 347 348 349
  {
    switch (u.format) {
    case 0: return u.format0.get_value (glyph_id, num_glyphs);
    case 2: return u.format2.get_value (glyph_id);
    case 4: return u.format4.get_value (glyph_id);
    case 6: return u.format6.get_value (glyph_id);
    case 8: return u.format8.get_value (glyph_id);
350
    default:return nullptr;
B
Behdad Esfahbod 已提交
351 352 353
    }
  }

354
  const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
355
  {
B
Behdad Esfahbod 已提交
356 357 358 359 360 361 362
    switch (u.format) {
      /* Format 10 cannot return a pointer. */
      case 10: return u.format10.get_value_or_null (glyph_id);
      default:
      const T *v = get_value (glyph_id, num_glyphs);
      return v ? *v : Null(T);
    }
363 364
  }

365 366 367
  typename T::type get_class (hb_codepoint_t glyph_id,
			      unsigned int num_glyphs,
			      unsigned int outOfRange) const
368 369 370 371 372
  {
    const T *v = get_value (glyph_id, num_glyphs);
    return v ? *v : outOfRange;
  }

373
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
374 375 376 377 378 379 380 381 382
  {
    TRACE_SANITIZE (this);
    if (!u.format.sanitize (c)) return_trace (false);
    switch (u.format) {
    case 0: return_trace (u.format0.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    case 4: return_trace (u.format4.sanitize (c));
    case 6: return_trace (u.format6.sanitize (c));
    case 8: return_trace (u.format8.sanitize (c));
B
Behdad Esfahbod 已提交
383
    case 10: return_trace (u.format10.sanitize (c));
B
Behdad Esfahbod 已提交
384 385 386
    default:return_trace (true);
    }
  }
387
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
388 389 390 391 392 393 394 395 396
  {
    TRACE_SANITIZE (this);
    if (!u.format.sanitize (c)) return_trace (false);
    switch (u.format) {
    case 0: return_trace (u.format0.sanitize (c, base));
    case 2: return_trace (u.format2.sanitize (c, base));
    case 4: return_trace (u.format4.sanitize (c, base));
    case 6: return_trace (u.format6.sanitize (c, base));
    case 8: return_trace (u.format8.sanitize (c, base));
B
Behdad Esfahbod 已提交
397
    case 10: return_trace (false); /* We don't support format10 here currently. */
398 399 400
    default:return_trace (true);
    }
  }
B
Behdad Esfahbod 已提交
401 402 403

  protected:
  union {
B
Behdad Esfahbod 已提交
404
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
405 406 407 408 409
  LookupFormat0<T>	format0;
  LookupFormat2<T>	format2;
  LookupFormat4<T>	format4;
  LookupFormat6<T>	format6;
  LookupFormat8<T>	format8;
B
Behdad Esfahbod 已提交
410
  LookupFormat10<T>	format10;
B
Behdad Esfahbod 已提交
411 412
  } u;
  public:
413
  DEFINE_SIZE_UNION (2, format);
B
Behdad Esfahbod 已提交
414
};
415 416 417 418 419 420
/* Lookup 0 has unbounded size (dependant on num_glyphs).  So we need to defined
 * special NULL objects for Lookup<> objects, but since it's template our macros
 * don't work.  So we have to hand-code them here.  UGLY. */
} /* Close namespace. */
/* Ugly hand-coded null objects for template Lookup<> :(. */
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
421
template <typename T>
422
struct Null<AAT::Lookup<T>> {
423 424 425
  static AAT::Lookup<T> const & get_null ()
  { return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
};
426
namespace AAT {
B
Behdad Esfahbod 已提交
427

428
enum { DELETED_GLYPH = 0xFFFF };
B
Behdad Esfahbod 已提交
429

430
/*
B
Minor  
Behdad Esfahbod 已提交
431
 * (Extended) State Table
432 433 434 435 436
 */

template <typename T>
struct Entry
{
437
  bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
438 439
  {
    TRACE_SANITIZE (this);
440 441 442
    /* Note, we don't recurse-sanitize data because we don't access it.
     * That said, in our DEFINE_SIZE_STATIC we access T::static_size,
     * which ensures that data has a simple sanitize(). To be determined
443 444
     * if I need to remove that as well.
     *
B
Behdad Esfahbod 已提交
445 446 447 448
     * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC
     * assertion wouldn't be checked, hence the line below. */
    static_assert (T::static_size, "");

449
    return_trace (c->check_struct (this));
450 451 452
  }

  public:
453 454 455
  HBUINT16	newState;	/* Byte offset from beginning of state table
				 * to the new state. Really?!?! Or just state
				 * number?  The latter in morx for sure. */
456 457 458 459 460 461 462 463 464
  HBUINT16	flags;		/* Table specific. */
  T		data;		/* Optional offsets to per-glyph tables. */
  public:
  DEFINE_SIZE_STATIC (4 + T::static_size);
};

template <>
struct Entry<void>
{
465
  bool sanitize (hb_sanitize_context_t *c, unsigned int count /*XXX Unused?*/) const
466 467 468 469 470 471 472 473 474 475 476 477
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this));
  }

  public:
  HBUINT16	newState;	/* Byte offset from beginning of state table to the new state. */
  HBUINT16	flags;		/* Table specific. */
  public:
  DEFINE_SIZE_STATIC (4);
};

478
template <typename Types, typename Extra>
479 480
struct StateTable
{
481 482
  typedef typename Types::HBUINT HBUINT;
  typedef typename Types::HBUSHORT HBUSHORT;
483
  typedef typename Types::ClassTypeNarrow ClassType;
484

485 486 487 488 489 490 491 492 493 494 495 496 497
  enum State
  {
    STATE_START_OF_TEXT = 0,
    STATE_START_OF_LINE = 1,
  };
  enum Class
  {
    CLASS_END_OF_TEXT = 0,
    CLASS_OUT_OF_BOUNDS = 1,
    CLASS_DELETED_GLYPH = 2,
    CLASS_END_OF_LINE = 3,
  };

498
  int new_state (unsigned int newState) const
B
Behdad Esfahbod 已提交
499
  { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; }
B
Behdad Esfahbod 已提交
500

501
  unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
B
Behdad Esfahbod 已提交
502
  {
503
    if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH;
B
Behdad Esfahbod 已提交
504
    return (this+classTable).get_class (glyph_id, num_glyphs, 1);
B
Behdad Esfahbod 已提交
505
  }
506

507
  const Entry<Extra> *get_entries () const
508
  { return (this+entryTable).arrayZ; }
509

510
  const Entry<Extra> &get_entry (int state, unsigned int klass) const
511
  {
512
    if (unlikely (klass >= nClasses))
513
      klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
B
Behdad Esfahbod 已提交
514

515
    const HBUSHORT *states = (this+stateArrayTable).arrayZ;
516 517
    const Entry<Extra> *entries = (this+entryTable).arrayZ;

B
Behdad Esfahbod 已提交
518
    unsigned int entry = states[state * nClasses + klass];
519
    DEBUG_MSG (APPLY, nullptr, "e%u", entry);
520

521
    return entries[entry];
522 523
  }

524 525
  bool sanitize (hb_sanitize_context_t *c,
		 unsigned int *num_entries_out = nullptr) const
526 527
  {
    TRACE_SANITIZE (this);
528
    if (unlikely (!(c->check_struct (this) &&
B
Behdad Esfahbod 已提交
529
		    nClasses >= 4 /* Ensure pre-defined classes fit.  */ &&
530
		    classTable.sanitize (c, this)))) return_trace (false);
B
Behdad Esfahbod 已提交
531

532
    const HBUSHORT *states = (this+stateArrayTable).arrayZ;
B
Behdad Esfahbod 已提交
533 534
    const Entry<Extra> *entries = (this+entryTable).arrayZ;

B
Behdad Esfahbod 已提交
535
    unsigned int num_classes = nClasses;
536 537 538
    if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
      return_trace (false);
    unsigned int row_stride = num_classes * states[0].static_size;
B
Behdad Esfahbod 已提交
539

540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
    /* Apple 'kern' table has this peculiarity:
     *
     * "Because the stateTableOffset in the state table header is (strictly
     * speaking) redundant, some 'kern' tables use it to record an initial
     * state where that should not be StartOfText. To determine if this is
     * done, calculate what the stateTableOffset should be. If it's different
     * from the actual stateTableOffset, use it as the initial state."
     *
     * We implement this by calling the initial state zero, but allow *negative*
     * states if the start state indeed was not the first state.  Since the code
     * is shared, this will also apply to 'mort' table.  The 'kerx' / 'morx'
     * tables are not affected since those address states by index, not offset.
     */

    int min_state = 0;
    int max_state = 0;
B
Behdad Esfahbod 已提交
556 557
    unsigned int num_entries = 0;

558 559
    int state_pos = 0;
    int state_neg = 0;
B
Behdad Esfahbod 已提交
560
    unsigned int entry = 0;
561
    while (min_state < state_neg || state_pos <= max_state)
B
Behdad Esfahbod 已提交
562
    {
563 564 565 566 567
      if (min_state < state_neg)
      {
	/* Negative states. */
	if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes)))
	  return_trace (false);
568 569 570
	if (unlikely (!c->check_range (&states[min_state * num_classes],
				       -min_state,
				       row_stride)))
571
	  return_trace (false);
B
Behdad Esfahbod 已提交
572
	if ((c->max_ops -= state_neg - min_state) <= 0)
573 574 575 576 577 578
	  return_trace (false);
	{ /* Sweep new states. */
	  const HBUSHORT *stop = &states[min_state * num_classes];
	  if (unlikely (stop > states))
	    return_trace (false);
	  for (const HBUSHORT *p = states; stop < p; p--)
579
	    num_entries = hb_max (num_entries, *(p - 1) + 1);
580 581 582
	  state_neg = min_state;
	}
      }
B
Behdad Esfahbod 已提交
583

584 585 586
      if (state_pos <= max_state)
      {
	/* Positive states. */
587 588 589
	if (unlikely (!c->check_range (states,
				       max_state + 1,
				       row_stride)))
590
	  return_trace (false);
B
Behdad Esfahbod 已提交
591
	if ((c->max_ops -= max_state - state_pos + 1) <= 0)
592 593 594 595 596 597 598 599
	  return_trace (false);
	{ /* Sweep new states. */
	  if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes)))
	    return_trace (false);
	  const HBUSHORT *stop = &states[(max_state + 1) * num_classes];
	  if (unlikely (stop < states))
	    return_trace (false);
	  for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
600
	    num_entries = hb_max (num_entries, *p + 1);
601 602
	  state_pos = max_state + 1;
	}
B
Behdad Esfahbod 已提交
603 604
      }

605
      if (unlikely (!c->check_array (entries, num_entries)))
B
Behdad Esfahbod 已提交
606
	return_trace (false);
B
Behdad Esfahbod 已提交
607
      if ((c->max_ops -= num_entries - entry) <= 0)
B
Behdad Esfahbod 已提交
608
	return_trace (false);
B
Behdad Esfahbod 已提交
609 610 611
      { /* Sweep new entries. */
	const Entry<Extra> *stop = &entries[num_entries];
	for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
B
Behdad Esfahbod 已提交
612
	{
613
	  int newState = new_state (p->newState);
614 615
	  min_state = hb_min (min_state, newState);
	  max_state = hb_max (max_state, newState);
B
Behdad Esfahbod 已提交
616
	}
B
Behdad Esfahbod 已提交
617 618 619 620
	entry = num_entries;
      }
    }

621 622 623
    if (num_entries_out)
      *num_entries_out = num_entries;

B
Behdad Esfahbod 已提交
624
    return_trace (true);
625 626 627
  }

  protected:
628
  HBUINT	nClasses;	/* Number of classes, which is the number of indices
629
				 * in a single line in the state array. */
630
  NNOffsetTo<ClassType, HBUINT>
631
		classTable;	/* Offset to the class table. */
632
  NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
633
		stateArrayTable;/* Offset to the state array. */
634
  NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
635 636 637
		entryTable;	/* Offset to the entry array. */

  public:
B
Behdad Esfahbod 已提交
638
  DEFINE_SIZE_STATIC (4 * sizeof (HBUINT));
639 640
};

641
template <typename HBUCHAR>
642 643
struct ClassTable
{
644
  unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const
645
  {
B
Behdad Esfahbod 已提交
646 647
    unsigned int i = glyph_id - firstGlyph;
    return i >= classArray.len ? outOfRange : classArray.arrayZ[i];
648
  }
649 650 651
  unsigned int get_class (hb_codepoint_t glyph_id,
			  unsigned int num_glyphs HB_UNUSED,
			  unsigned int outOfRange) const
652 653 654
  {
    return get_class (glyph_id, outOfRange);
  }
655
  bool sanitize (hb_sanitize_context_t *c) const
656 657
  {
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
658
    return_trace (c->check_struct (this) && classArray.sanitize (c));
659 660
  }
  protected:
B
Behdad Esfahbod 已提交
661
  GlyphID		firstGlyph;	/* First glyph index included in the trimmed array. */
662
  ArrayOf<HBUCHAR>	classArray;	/* The class codes (indexed by glyph index minus
B
Behdad Esfahbod 已提交
663
					 * firstGlyph). */
664
  public:
B
Behdad Esfahbod 已提交
665
  DEFINE_SIZE_ARRAY (4, classArray);
666 667
};

B
Behdad Esfahbod 已提交
668
struct ObsoleteTypes
669
{
670
  static constexpr bool extended = false;
671 672
  typedef HBUINT16 HBUINT;
  typedef HBUINT8 HBUSHORT;
673 674
  typedef ClassTable<HBUINT8> ClassTypeNarrow;
  typedef ClassTable<HBUINT16> ClassTypeWide;
675

B
Behdad Esfahbod 已提交
676
  template <typename T>
677 678 679
  static unsigned int offsetToIndex (unsigned int offset,
				     const void *base,
				     const T *array)
B
Behdad Esfahbod 已提交
680 681 682 683
  {
    return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
  }
  template <typename T>
684 685 686
  static unsigned int byteOffsetToIndex (unsigned int offset,
					 const void *base,
					 const T *array)
687 688 689 690
  {
    return offsetToIndex (offset, base, array);
  }
  template <typename T>
691 692 693
  static unsigned int wordOffsetToIndex (unsigned int offset,
					 const void *base,
					 const T *array)
B
Behdad Esfahbod 已提交
694 695 696
  {
    return offsetToIndex (2 * offset, base, array);
  }
697
};
B
Behdad Esfahbod 已提交
698
struct ExtendedTypes
699
{
700
  static constexpr bool extended = true;
701 702
  typedef HBUINT32 HBUINT;
  typedef HBUINT16 HBUSHORT;
703 704
  typedef Lookup<HBUINT16> ClassTypeNarrow;
  typedef Lookup<HBUINT16> ClassTypeWide;
705

B
Behdad Esfahbod 已提交
706
  template <typename T>
707
  static unsigned int offsetToIndex (unsigned int offset,
B
Behdad Esfahbod 已提交
708 709
				     const void *base HB_UNUSED,
				     const T *array HB_UNUSED)
B
Behdad Esfahbod 已提交
710 711 712 713
  {
    return offset;
  }
  template <typename T>
714
  static unsigned int byteOffsetToIndex (unsigned int offset,
B
Behdad Esfahbod 已提交
715 716
					 const void *base HB_UNUSED,
					 const T *array HB_UNUSED)
717 718 719 720
  {
    return offset / 2;
  }
  template <typename T>
721
  static unsigned int wordOffsetToIndex (unsigned int offset,
B
Behdad Esfahbod 已提交
722 723
					 const void *base HB_UNUSED,
					 const T *array HB_UNUSED)
B
Behdad Esfahbod 已提交
724 725 726
  {
    return offset;
  }
727 728 729
};

template <typename Types, typename EntryData>
730 731
struct StateTableDriver
{
732 733 734
  StateTableDriver (const StateTable<Types, EntryData> &machine_,
		    hb_buffer_t *buffer_,
		    hb_face_t *face_) :
735 736
	      machine (machine_),
	      buffer (buffer_),
B
Behdad Esfahbod 已提交
737
	      num_glyphs (face_->get_num_glyphs ()) {}
738 739

  template <typename context_t>
740
  void drive (context_t *c)
741
  {
742 743 744
    if (!c->in_place)
      buffer->clear_output ();

745
    int state = StateTable<Types, EntryData>::STATE_START_OF_TEXT;
B
Behdad Esfahbod 已提交
746
    for (buffer->idx = 0; buffer->successful;)
747
    {
748
      unsigned int klass = buffer->idx < buffer->len ?
B
Behdad Esfahbod 已提交
749
			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
750
			   (unsigned) StateTable<Types, EntryData>::CLASS_END_OF_TEXT;
751
      DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
B
Behdad Esfahbod 已提交
752
      const Entry<EntryData> &entry = machine.get_entry (state, klass);
753

B
Behdad Esfahbod 已提交
754
      /* Unsafe-to-break before this if not in state 0, as things might
755 756 757 758
       * go differently if we start from state 0 here.
       *
       * Ugh.  The indexing here is ugly... */
      if (state && buffer->backtrack_len () && buffer->idx < buffer->len)
B
Behdad Esfahbod 已提交
759
      {
760 761 762
	/* If there's no action and we're just epsilon-transitioning to state 0,
	 * safe to break. */
	if (c->is_actionable (this, entry) ||
B
Behdad Esfahbod 已提交
763 764
	    !(entry.newState == StateTable<Types, EntryData>::STATE_START_OF_TEXT &&
	      entry.flags == context_t::DontAdvance))
765
	  buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
B
Behdad Esfahbod 已提交
766 767 768 769 770
      }

      /* Unsafe-to-break if end-of-text would kick in here. */
      if (buffer->idx + 2 <= buffer->len)
      {
B
Behdad Esfahbod 已提交
771
	const Entry<EntryData> &end_entry = machine.get_entry (state, StateTable<Types, EntryData>::CLASS_END_OF_TEXT);
B
Behdad Esfahbod 已提交
772 773 774 775
	if (c->is_actionable (this, end_entry))
	  buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
      }

776
      c->transition (this, entry);
777

B
Behdad Esfahbod 已提交
778
      state = machine.new_state (entry.newState);
779
      DEBUG_MSG (APPLY, nullptr, "s%d", state);
780 781

      if (buffer->idx == buffer->len)
B
Behdad Esfahbod 已提交
782
	break;
783

B
Behdad Esfahbod 已提交
784
      if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0)
B
Behdad Esfahbod 已提交
785
	buffer->next_glyph ();
786 787
    }

788 789
    if (!c->in_place)
    {
790 791
      for (; buffer->successful && buffer->idx < buffer->len;)
	buffer->next_glyph ();
792
      buffer->swap_buffers ();
793
    }
794 795 796
  }

  public:
797
  const StateTable<Types, EntryData> &machine;
798 799 800 801
  hb_buffer_t *buffer;
  unsigned int num_glyphs;
};

802

803
struct ankr;
804 805 806 807

struct hb_aat_apply_context_t :
       hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
808
  const char *get_name () { return "APPLY"; }
809
  template <typename T>
B
Behdad Esfahbod 已提交
810
  return_t dispatch (const T &obj) { return obj.apply (this); }
811
  static return_t default_return_value () { return false; }
812 813
  bool stop_sublookup_iteration (return_t r) const { return r; }

B
Behdad Esfahbod 已提交
814
  const hb_ot_shape_plan_t *plan;
815 816 817
  hb_font_t *font;
  hb_face_t *face;
  hb_buffer_t *buffer;
818
  hb_sanitize_context_t sanitizer;
819
  const ankr *ankr_table;
820

B
Behdad Esfahbod 已提交
821 822 823 824
  /* Unused. For debug tracing only. */
  unsigned int lookup_index;
  unsigned int debug_depth;

B
Behdad Esfahbod 已提交
825
  HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
826 827 828
				      hb_font_t *font_,
				      hb_buffer_t *buffer_,
				      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)));
829

830
  HB_INTERNAL ~hb_aat_apply_context_t ();
B
Behdad Esfahbod 已提交
831

B
Behdad Esfahbod 已提交
832
  HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
833

834
  void set_lookup_index (unsigned int i) { lookup_index = i; }
835 836 837
};


838 839 840
} /* namespace AAT */


841
#endif /* HB_AAT_LAYOUT_COMMON_HH */