hb-aat-layout-common.hh 15.6 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 32 33 34 35 36 37


namespace AAT {

using namespace OT;


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

template <typename T> struct Lookup;

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

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

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
59
    return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
B
Behdad Esfahbod 已提交
60 61 62
  }

  protected:
B
Behdad Esfahbod 已提交
63
  HBUINT16	format;		/* Format identifier--format = 0 */
B
Behdad Esfahbod 已提交
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
  UnsizedArrayOf<T>
		arrayZ;		/* Array of lookup values, indexed by glyph index. */
  public:
  DEFINE_SIZE_ARRAY (2, arrayZ);
};


template <typename T>
struct LookupSegmentSingle
{
  inline int cmp (hb_codepoint_t g) const {
    return g < first ? -1 : g <= last ? 0 : +1 ;
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && value.sanitize (c));
  }

  GlyphID	last;		/* Last GlyphID in this segment */
  GlyphID	first;		/* First GlyphID in this segment */
  T		value;		/* The lookup value (only one) */
  public:
88
  DEFINE_SIZE_STATIC (4 + T::static_size);
B
Behdad Esfahbod 已提交
89 90 91 92 93 94 95 96
};

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

  private:
97
  inline const T* get_value (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
98 99
  {
    const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id);
100
    return v ? &v->value : nullptr;
B
Behdad Esfahbod 已提交
101 102 103 104 105 106 107 108 109
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (segments.sanitize (c));
  }

  protected:
B
Behdad Esfahbod 已提交
110
  HBUINT16	format;		/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
111
  VarSizedBinSearchArrayOf<LookupSegmentSingle<T> >
B
Behdad Esfahbod 已提交
112 113 114 115 116 117 118 119 120 121
		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
{
122
  inline const T* get_value (hb_codepoint_t glyph_id, const void *base) const
B
Behdad Esfahbod 已提交
123
  {
124
    return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr;
B
Behdad Esfahbod 已提交
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
  }

  inline int cmp (hb_codepoint_t g) const {
    return g < first ? -1 : g <= last ? 0 : +1 ;
  }

  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) &&
		  first <= last &&
		  valuesZ.sanitize (c, base, last - first + 1));
  }

  GlyphID	last;		/* Last GlyphID in this segment */
  GlyphID	first;		/* First GlyphID in this segment */
141
  OffsetTo<UnsizedArrayOf<T>, HBUINT16, false>
B
Behdad Esfahbod 已提交
142 143 144 145 146 147 148 149 150 151 152 153
		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:
154
  inline const T* get_value (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
155 156
  {
    const LookupSegmentArray<T> *v = segments.bsearch (glyph_id);
157
    return v ? v->get_value (glyph_id, this) : nullptr;
B
Behdad Esfahbod 已提交
158 159 160 161 162 163 164 165 166
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (segments.sanitize (c, this));
  }

  protected:
167
  HBUINT16	format;		/* Format identifier--format = 4 */
B
Behdad Esfahbod 已提交
168
  VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
B
Behdad Esfahbod 已提交
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
		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
{
  inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && value.sanitize (c));
  }

  GlyphID	glyph;		/* Last GlyphID */
  T		value;		/* The lookup value (only one) */
  public:
190
  DEFINE_SIZE_STATIC (2 + T::static_size);
B
Behdad Esfahbod 已提交
191 192 193 194 195 196 197 198
};

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

  private:
199
  inline const T* get_value (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
200 201
  {
    const LookupSingle<T> *v = entries.bsearch (glyph_id);
202
    return v ? &v->value : nullptr;
B
Behdad Esfahbod 已提交
203 204 205 206 207 208 209 210 211
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (entries.sanitize (c));
  }

  protected:
B
Behdad Esfahbod 已提交
212
  HBUINT16	format;		/* Format identifier--format = 6 */
B
Behdad Esfahbod 已提交
213
  VarSizedBinSearchArrayOf<LookupSingle<T> >
B
Behdad Esfahbod 已提交
214 215 216 217 218 219 220 221 222 223 224
		entries;	/* The actual entries, sorted by glyph index. */
  public:
  DEFINE_SIZE_ARRAY (8, entries);
};

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

  private:
225
  inline const T* get_value (hb_codepoint_t glyph_id) const
B
Behdad Esfahbod 已提交
226
  {
227
    return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? &valueArrayZ[glyph_id - firstGlyph] : nullptr;
B
Behdad Esfahbod 已提交
228 229 230 231 232 233 234 235 236
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount));
  }

  protected:
B
Behdad Esfahbod 已提交
237
  HBUINT16	format;		/* Format identifier--format = 6 */
B
Behdad Esfahbod 已提交
238
  GlyphID	firstGlyph;	/* First glyph index included in the trimmed array. */
B
Behdad Esfahbod 已提交
239
  HBUINT16	glyphCount;	/* Total number of glyphs (equivalent to the last
B
Behdad Esfahbod 已提交
240 241 242 243 244 245 246 247 248 249 250
				 * 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);
};

template <typename T>
struct Lookup
{
251
  inline const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
B
Behdad Esfahbod 已提交
252 253 254 255 256 257 258
  {
    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);
259
    default:return nullptr;
B
Behdad Esfahbod 已提交
260 261 262
    }
  }

263 264 265 266 267 268
  inline const T& get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
  {
    const T *v = get_value (glyph_id, num_glyphs);
    return v ? *v : Null(T);
  }

B
Behdad Esfahbod 已提交
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    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));
    default:return_trace (true);
    }
  }

  protected:
  union {
B
Behdad Esfahbod 已提交
285
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
286 287 288 289 290 291 292 293 294 295 296
  LookupFormat0<T>	format0;
  LookupFormat2<T>	format2;
  LookupFormat4<T>	format4;
  LookupFormat6<T>	format6;
  LookupFormat8<T>	format8;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};


297
/*
B
Behdad Esfahbod 已提交
298
 * Extended State Table
299 300 301 302 303 304 305 306
 */

template <typename T>
struct Entry
{
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
  {
    TRACE_SANITIZE (this);
307 308 309 310 311
    /* 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
     * if I need to remove that as well. */
    return_trace (c->check_struct (this));
312 313 314
  }

  public:
315 316 317
  HBUINT16	newState;	/* Byte offset from beginning of state table
				 * to the new state. Really?!?! Or just state
				 * number?  The latter in morx for sure. */
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
  HBUINT16	flags;		/* Table specific. */
  T		data;		/* Optional offsets to per-glyph tables. */
  public:
  DEFINE_SIZE_STATIC (4 + T::static_size);
};

template <>
struct Entry<void>
{
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
  {
    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);
};

B
Behdad Esfahbod 已提交
340
template <typename Extra>
341 342
struct StateTable
{
343 344 345 346 347 348 349 350 351 352 353 354 355
  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,
  };

356
  inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
B
Behdad Esfahbod 已提交
357 358
  {
    const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
B
Behdad Esfahbod 已提交
359
    return v ? (unsigned) *v : (unsigned) CLASS_OUT_OF_BOUNDS;
B
Behdad Esfahbod 已提交
360
  }
361

362 363 364 365 366 367
  inline const Entry<Extra> *get_entries () const
  {
    return (this+entryTable).arrayZ;
  }

  inline const Entry<Extra> *get_entryZ (unsigned int state, unsigned int klass) const
368
  {
B
Behdad Esfahbod 已提交
369 370
    if (unlikely (klass >= nClasses)) return nullptr;

B
Behdad Esfahbod 已提交
371
    const HBUINT16 *states = (this+stateArrayTable).arrayZ;
372 373
    const Entry<Extra> *entries = (this+entryTable).arrayZ;

B
Behdad Esfahbod 已提交
374
    unsigned int entry = states[state * nClasses + klass];
375

B
Behdad Esfahbod 已提交
376
    return &entries[entry];
377 378
  }

379 380
  inline bool sanitize (hb_sanitize_context_t *c,
			unsigned int *num_entries_out = nullptr) const
381 382
  {
    TRACE_SANITIZE (this);
383 384
    if (unlikely (!(c->check_struct (this) &&
		    classTable.sanitize (c, this)))) return_trace (false);
B
Behdad Esfahbod 已提交
385

B
Behdad Esfahbod 已提交
386
    const HBUINT16 *states = (this+stateArrayTable).arrayZ;
B
Behdad Esfahbod 已提交
387 388
    const Entry<Extra> *entries = (this+entryTable).arrayZ;

B
Behdad Esfahbod 已提交
389 390
    unsigned int num_classes = nClasses;

B
Behdad Esfahbod 已提交
391 392 393 394 395 396 397
    unsigned int num_states = 1;
    unsigned int num_entries = 0;

    unsigned int state = 0;
    unsigned int entry = 0;
    while (state < num_states)
    {
B
Behdad Esfahbod 已提交
398 399 400
      if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size)))
	return_trace (false);

B
Behdad Esfahbod 已提交
401
      if (unlikely (!c->check_array (states,
402
				     num_states,
B
Behdad Esfahbod 已提交
403
				     num_classes * states[0].static_size)))
B
Behdad Esfahbod 已提交
404 405
	return_trace (false);
      { /* Sweep new states. */
B
Behdad Esfahbod 已提交
406 407
	const HBUINT16 *stop = &states[num_states * num_classes];
	for (const HBUINT16 *p = &states[state * num_classes]; p < stop; p++)
B
Behdad Esfahbod 已提交
408 409 410 411
	  num_entries = MAX<unsigned int> (num_entries, *p + 1);
	state = num_states;
      }

412
      if (unlikely (!c->check_array (entries, num_entries)))
B
Behdad Esfahbod 已提交
413 414 415 416 417 418 419 420 421
	return_trace (false);
      { /* Sweep new entries. */
	const Entry<Extra> *stop = &entries[num_entries];
	for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
	  num_states = MAX<unsigned int> (num_states, p->newState + 1);
	entry = num_entries;
      }
    }

422 423 424
    if (num_entries_out)
      *num_entries_out = num_entries;

B
Behdad Esfahbod 已提交
425
    return_trace (true);
426 427 428
  }

  protected:
B
Behdad Esfahbod 已提交
429
  HBUINT32	nClasses;	/* Number of classes, which is the number of indices
430
				 * in a single line in the state array. */
431
  LOffsetTo<Lookup<HBUINT16>, false>
432
		classTable;	/* Offset to the class table. */
433
  LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
434
		stateArrayTable;/* Offset to the state array. */
435
  LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false>
436 437 438
		entryTable;	/* Offset to the entry array. */

  public:
B
Behdad Esfahbod 已提交
439
  DEFINE_SIZE_STATIC (16);
440 441
};

442 443 444 445 446 447 448 449
template <typename EntryData>
struct StateTableDriver
{
  inline StateTableDriver (const StateTable<EntryData> &machine_,
			   hb_buffer_t *buffer_,
			   hb_face_t *face_) :
	      machine (machine_),
	      buffer (buffer_),
B
Behdad Esfahbod 已提交
450
	      num_glyphs (face_->get_num_glyphs ()) {}
451 452 453 454

  template <typename context_t>
  inline void drive (context_t *c)
  {
455 456 457
    if (!c->in_place)
      buffer->clear_output ();

458
    unsigned int state = StateTable<EntryData>::STATE_START_OF_TEXT;
459
    bool last_was_dont_advance = false;
460
    for (buffer->idx = 0;;)
461
    {
462
      unsigned int klass = buffer->idx < buffer->len ?
B
Behdad Esfahbod 已提交
463
			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
464
			   (unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
465 466 467 468
      const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
      if (unlikely (!entry))
	break;

B
Behdad Esfahbod 已提交
469
      /* Unsafe-to-break before this if not in state 0, as things might
470 471 472 473
       * 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 已提交
474
      {
475 476 477
	/* 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 已提交
478 479
	    !(entry->newState == StateTable<EntryData>::STATE_START_OF_TEXT &&
	      entry->flags == context_t::DontAdvance))
480
	  buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
B
Behdad Esfahbod 已提交
481 482 483 484 485 486 487 488 489 490
      }

      /* Unsafe-to-break if end-of-text would kick in here. */
      if (buffer->idx + 2 <= buffer->len)
      {
	const Entry<EntryData> *end_entry = machine.get_entryZ (state, 0);
	if (c->is_actionable (this, end_entry))
	  buffer->unsafe_to_break (buffer->idx, buffer->idx + 2);
      }

491 492
      if (unlikely (!c->transition (this, entry)))
        break;
493

494 495
      if (unlikely (!buffer->successful)) return;

B
Behdad Esfahbod 已提交
496
      last_was_dont_advance = (entry->flags & context_t::DontAdvance) && buffer->max_ops-- > 0;
497

498 499 500 501 502
      state = entry->newState;

      if (buffer->idx == buffer->len)
        break;

503 504
      if (!last_was_dont_advance)
        buffer->next_glyph ();
505 506
    }

507 508
    if (!c->in_place)
    {
509
      for (; buffer->idx < buffer->len;)
510
        buffer->next_glyph ();
511
      buffer->swap_buffers ();
512
    }
513 514 515 516 517 518 519 520
  }

  public:
  const StateTable<EntryData> &machine;
  hb_buffer_t *buffer;
  unsigned int num_glyphs;
};

521

522
struct ankr;
523 524 525 526 527 528 529 530 531 532

struct hb_aat_apply_context_t :
       hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
{
  inline const char *get_name (void) { return "APPLY"; }
  template <typename T>
  inline return_t dispatch (const T &obj) { return obj.apply (this); }
  static return_t default_return_value (void) { return false; }
  bool stop_sublookup_iteration (return_t r) const { return r; }

B
Behdad Esfahbod 已提交
533
  hb_ot_shape_plan_t *plan;
534 535 536
  hb_font_t *font;
  hb_face_t *face;
  hb_buffer_t *buffer;
537
  hb_sanitize_context_t sanitizer;
538
  const ankr &ankr_table;
539
  const char *ankr_end;
540

B
Behdad Esfahbod 已提交
541 542 543 544
  /* Unused. For debug tracing only. */
  unsigned int lookup_index;
  unsigned int debug_depth;

B
Behdad Esfahbod 已提交
545 546
  inline hb_aat_apply_context_t (hb_ot_shape_plan_t *plan_,
				 hb_font_t *font_,
547
				 hb_buffer_t *buffer_,
B
Behdad Esfahbod 已提交
548
				 hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)),
549 550
				 const ankr &ankr_table_ = Null(ankr),
				 const char *ankr_end_ = nullptr) :
B
Behdad Esfahbod 已提交
551
		plan (plan_), font (font_), face (font->face), buffer (buffer_),
552 553 554
		sanitizer (),
		ankr_table (ankr_table_), ankr_end (ankr_end_),
		lookup_index (0), debug_depth (0)
555
  {
B
Behdad Esfahbod 已提交
556
    sanitizer.init (blob);
557
    sanitizer.set_num_glyphs (face->get_num_glyphs ());
558
    sanitizer.start_processing ();
B
Behdad Esfahbod 已提交
559
    sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
560 561
  }

B
Behdad Esfahbod 已提交
562 563
  inline void set_lookup_index (unsigned int i) { lookup_index = i; }

564 565 566 567
  inline ~hb_aat_apply_context_t (void)
  {
    sanitizer.end_processing ();
  }
568 569 570
};


571 572 573
} /* namespace AAT */


574
#endif /* HB_AAT_LAYOUT_COMMON_HH */