hb-aat-layout-common.hh 15.0 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:
B
Behdad Esfahbod 已提交
167
  HBUINT16	format;		/* Format identifier--format = 2 */
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 (4 + 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 269 270 271 272 273 274 275 276 277 278
    }
  }

  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 已提交
279
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
280 281 282 283 284 285 286 287 288 289 290
  LookupFormat0<T>	format0;
  LookupFormat2<T>	format2;
  LookupFormat4<T>	format4;
  LookupFormat6<T>	format6;
  LookupFormat8<T>	format8;
  } u;
  public:
  DEFINE_SIZE_UNION (2, format);
};


291
/*
B
Behdad Esfahbod 已提交
292
 * Extended State Table
293 294 295 296 297 298 299 300
 */

template <typename T>
struct Entry
{
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
  {
    TRACE_SANITIZE (this);
301 302 303 304 305
    /* 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));
306 307 308
  }

  public:
309 310 311
  HBUINT16	newState;	/* Byte offset from beginning of state table
				 * to the new state. Really?!?! Or just state
				 * number?  The latter in morx for sure. */
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
  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 已提交
334
template <typename Extra>
335 336
struct StateTable
{
337 338 339 340 341 342 343 344 345 346 347 348 349
  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,
  };

350
  inline unsigned int get_class (hb_codepoint_t glyph_id, unsigned int num_glyphs) const
B
Behdad Esfahbod 已提交
351 352
  {
    const HBUINT16 *v = (this+classTable).get_value (glyph_id, num_glyphs);
B
Behdad Esfahbod 已提交
353
    return v ? (unsigned) *v : (unsigned) CLASS_OUT_OF_BOUNDS;
B
Behdad Esfahbod 已提交
354
  }
355

356 357 358 359 360 361
  inline const Entry<Extra> *get_entries () const
  {
    return (this+entryTable).arrayZ;
  }

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

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

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

B
Behdad Esfahbod 已提交
370
    return &entries[entry];
371 372
  }

373 374
  inline bool sanitize (hb_sanitize_context_t *c,
			unsigned int *num_entries_out = nullptr) const
375 376
  {
    TRACE_SANITIZE (this);
377 378
    if (unlikely (!(c->check_struct (this) &&
		    classTable.sanitize (c, this)))) return_trace (false);
B
Behdad Esfahbod 已提交
379

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

    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 已提交
390
      if (unlikely (!c->check_array (states,
391 392
				     num_states,
				     states[0].static_size * nClasses)))
B
Behdad Esfahbod 已提交
393 394
	return_trace (false);
      { /* Sweep new states. */
B
Behdad Esfahbod 已提交
395 396
	const HBUINT16 *stop = &states[num_states * nClasses];
	for (const HBUINT16 *p = &states[state * nClasses]; p < stop; p++)
B
Behdad Esfahbod 已提交
397 398 399 400
	  num_entries = MAX<unsigned int> (num_entries, *p + 1);
	state = num_states;
      }

401
      if (unlikely (!c->check_array (entries, num_entries)))
B
Behdad Esfahbod 已提交
402 403 404 405 406 407 408 409 410
	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;
      }
    }

411 412 413
    if (num_entries_out)
      *num_entries_out = num_entries;

B
Behdad Esfahbod 已提交
414
    return_trace (true);
415 416 417
  }

  protected:
B
Behdad Esfahbod 已提交
418
  HBUINT32	nClasses;	/* Number of classes, which is the number of indices
419
				 * in a single line in the state array. */
420
  LOffsetTo<Lookup<HBUINT16>, false>
421
		classTable;	/* Offset to the class table. */
422
  LOffsetTo<UnsizedArrayOf<HBUINT16>, false>
423
		stateArrayTable;/* Offset to the state array. */
424
  LOffsetTo<UnsizedArrayOf<Entry<Extra> >, false>
425 426 427
		entryTable;	/* Offset to the entry array. */

  public:
B
Behdad Esfahbod 已提交
428
  DEFINE_SIZE_STATIC (16);
429 430
};

431 432 433 434 435 436 437 438
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 已提交
439
	      num_glyphs (face_->get_num_glyphs ()) {}
440 441 442 443

  template <typename context_t>
  inline void drive (context_t *c)
  {
444 445 446
    if (!c->in_place)
      buffer->clear_output ();

447
    unsigned int state = StateTable<EntryData>::STATE_START_OF_TEXT;
448
    bool last_was_dont_advance = false;
449
    for (buffer->idx = 0;;)
450
    {
451
      unsigned int klass = buffer->idx < buffer->len ?
B
Behdad Esfahbod 已提交
452
			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
453
			   (unsigned) StateTable<EntryData>::CLASS_END_OF_TEXT;
454 455 456 457
      const Entry<EntryData> *entry = machine.get_entryZ (state, klass);
      if (unlikely (!entry))
	break;

B
Behdad Esfahbod 已提交
458
      /* Unsafe-to-break before this if not in state 0, as things might
459 460 461 462
       * 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 已提交
463
      {
464 465 466
	/* 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 已提交
467 468
	    !(entry->newState == StateTable<EntryData>::STATE_START_OF_TEXT &&
	      entry->flags == context_t::DontAdvance))
469
	  buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1);
B
Behdad Esfahbod 已提交
470 471 472 473 474 475 476 477 478 479
      }

      /* 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);
      }

480 481
      if (unlikely (!c->transition (this, entry)))
        break;
482

483 484
      if (unlikely (!buffer->successful)) return;

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

487 488 489 490 491
      state = entry->newState;

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

492 493
      if (!last_was_dont_advance)
        buffer->next_glyph ();
494 495
    }

496 497
    if (!c->in_place)
    {
498
      for (; buffer->idx < buffer->len;)
499
        buffer->next_glyph ();
500
      buffer->swap_buffers ();
501
    }
502 503 504 505 506 507 508 509
  }

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

510

511 512 513 514 515 516 517 518 519 520

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 已提交
521
  hb_ot_shape_plan_t *plan;
522 523 524
  hb_font_t *font;
  hb_face_t *face;
  hb_buffer_t *buffer;
525
  hb_sanitize_context_t sanitizer;
526

B
Behdad Esfahbod 已提交
527 528 529 530
  /* Unused. For debug tracing only. */
  unsigned int lookup_index;
  unsigned int debug_depth;

B
Behdad Esfahbod 已提交
531 532
  inline hb_aat_apply_context_t (hb_ot_shape_plan_t *plan_,
				 hb_font_t *font_,
533 534
				 hb_buffer_t *buffer_,
				 hb_blob_t *table) :
B
Behdad Esfahbod 已提交
535
		plan (plan_), font (font_), face (font->face), buffer (buffer_),
B
Behdad Esfahbod 已提交
536
		sanitizer (), lookup_index (0), debug_depth (0)
537 538
  {
    sanitizer.init (table);
539
    sanitizer.set_num_glyphs (face->get_num_glyphs ());
540 541 542
    sanitizer.start_processing ();
  }

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

545 546 547 548
  inline ~hb_aat_apply_context_t (void)
  {
    sanitizer.end_processing ();
  }
549 550 551
};


552 553 554
} /* namespace AAT */


555
#endif /* HB_AAT_LAYOUT_COMMON_HH */