hb-ot-layout-gpos-table.hh 51.0 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3
 * Copyright © 2010,2012,2013  Google, Inc.
B
Behdad Esfahbod 已提交
4
 *
B
Behdad Esfahbod 已提交
5
 *  This is part of HarfBuzz, a text shaping library.
B
Behdad Esfahbod 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * 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
26
 * Google Author(s): Behdad Esfahbod
B
Behdad Esfahbod 已提交
27 28
 */

29 30
#ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
#define HB_OT_LAYOUT_GPOS_TABLE_HH
B
Behdad Esfahbod 已提交
31

32
#include "hb-ot-layout-gsubgpos-private.hh"
B
Behdad Esfahbod 已提交
33

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

B
Behdad Esfahbod 已提交
37

38
/* buffer **position** var allocations */
B
Behdad Esfahbod 已提交
39 40 41 42
#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */


B
Behdad Esfahbod 已提交
43 44
/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */

B
Behdad Esfahbod 已提交
45
typedef USHORT Value;
46

47
typedef Value ValueRecord[VAR];
B
Behdad Esfahbod 已提交
48

B
Behdad Esfahbod 已提交
49 50
struct ValueFormat : USHORT
{
B
Behdad Esfahbod 已提交
51
  enum Flags {
52 53 54 55 56 57 58 59
    xPlacement	= 0x0001,	/* Includes horizontal adjustment for placement */
    yPlacement	= 0x0002,	/* Includes vertical adjustment for placement */
    xAdvance	= 0x0004,	/* Includes horizontal adjustment for advance */
    yAdvance	= 0x0008,	/* Includes vertical adjustment for advance */
    xPlaDevice	= 0x0010,	/* Includes horizontal Device table for placement */
    yPlaDevice	= 0x0020,	/* Includes vertical Device table for placement */
    xAdvDevice	= 0x0040,	/* Includes horizontal Device table for advance */
    yAdvDevice	= 0x0080,	/* Includes vertical Device table for advance */
60
    ignored	= 0x0F00,	/* Was used in TrueType Open for MM fonts */
61
    reserved	= 0xF000,	/* For future use */
62

63
    devices	= 0x00F0	/* Mask for having any Device table */
B
WIP  
Behdad Esfahbod 已提交
64
  };
65

B
WIP  
Behdad Esfahbod 已提交
66
/* All fields are options.  Only those available advance the value pointer. */
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
#if 0
  SHORT		xPlacement;		/* Horizontal adjustment for
					 * placement--in design units */
  SHORT		yPlacement;		/* Vertical adjustment for
					 * placement--in design units */
  SHORT		xAdvance;		/* Horizontal adjustment for
					 * advance--in design units (only used
					 * for horizontal writing) */
  SHORT		yAdvance;		/* Vertical adjustment for advance--in
					 * design units (only used for vertical
					 * writing) */
  Offset	xPlaDevice;		/* Offset to Device table for
					 * horizontal placement--measured from
					 * beginning of PosTable (may be NULL) */
  Offset	yPlaDevice;		/* Offset to Device table for vertical
					 * placement--measured from beginning
					 * of PosTable (may be NULL) */
  Offset	xAdvDevice;		/* Offset to Device table for
					 * horizontal advance--measured from
					 * beginning of PosTable (may be NULL) */
  Offset	yAdvDevice;		/* Offset to Device table for vertical
					 * advance--measured from beginning of
					 * PosTable (may be NULL) */
#endif
91

B
Behdad Esfahbod 已提交
92
  inline unsigned int get_len (void) const
B
WIP  
Behdad Esfahbod 已提交
93
  { return _hb_popcount32 ((unsigned int) *this); }
B
Behdad Esfahbod 已提交
94
  inline unsigned int get_size (void) const
B
Behdad Esfahbod 已提交
95
  { return get_len () * Value::static_size; }
B
WIP  
Behdad Esfahbod 已提交
96

97
  void apply_value (hb_font_t            *font,
98
		    hb_direction_t        direction,
99 100 101
		    const void           *base,
		    const Value          *values,
		    hb_glyph_position_t  &glyph_pos) const
B
WIP  
Behdad Esfahbod 已提交
102 103 104
  {
    unsigned int x_ppem, y_ppem;
    unsigned int format = *this;
105
    hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
B
WIP  
Behdad Esfahbod 已提交
106 107 108

    if (!format) return;

B
Minor  
Behdad Esfahbod 已提交
109 110
    if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++));
    if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++));
111 112 113
    if (format & xAdvance) {
      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
    }
114
    /* y_advance values grow downward but font-space grows upward, hence negation */
115 116 117
    if (format & yAdvance) {
      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++;
    }
118

B
Behdad Esfahbod 已提交
119 120
    if (!has_device ()) return;

121 122
    x_ppem = font->x_ppem;
    y_ppem = font->y_ppem;
B
Behdad Esfahbod 已提交
123 124 125

    if (!x_ppem && !y_ppem) return;

126 127
    /* pixel -> fractional pixel */
    if (format & xPlaDevice) {
128
      if (x_ppem) glyph_pos.x_offset  += (base + get_device (values++)).get_x_delta (font); else values++;
129 130
    }
    if (format & yPlaDevice) {
131
      if (y_ppem) glyph_pos.y_offset  += (base + get_device (values++)).get_y_delta (font); else values++;
132 133
    }
    if (format & xAdvDevice) {
134
      if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++;
135 136
    }
    if (format & yAdvDevice) {
137
      /* y_advance values grow downward but font-space grows upward, hence negation */
138
      if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++;
139 140
    }
  }
B
WIP  
Behdad Esfahbod 已提交
141 142

  private:
B
Behdad Esfahbod 已提交
143
  inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
B
WIP  
Behdad Esfahbod 已提交
144 145 146 147 148 149 150
    unsigned int format = *this;

    if (format & xPlacement) values++;
    if (format & yPlacement) values++;
    if (format & xAdvance)   values++;
    if (format & yAdvance)   values++;

B
Behdad Esfahbod 已提交
151 152 153 154
    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
B
WIP  
Behdad Esfahbod 已提交
155 156 157 158

    return true;
  }

B
Behdad Esfahbod 已提交
159 160 161 162 163 164 165 166
  static inline OffsetTo<Device>& get_device (Value* value)
  { return *CastP<OffsetTo<Device> > (value); }
  static inline const OffsetTo<Device>& get_device (const Value* value)
  { return *CastP<OffsetTo<Device> > (value); }

  static inline const SHORT& get_short (const Value* value)
  { return *CastP<SHORT> (value); }

B
WIP  
Behdad Esfahbod 已提交
167 168
  public:

B
Behdad Esfahbod 已提交
169
  inline bool has_device (void) const {
B
WIP  
Behdad Esfahbod 已提交
170 171 172 173
    unsigned int format = *this;
    return (format & devices) != 0;
  }

B
Behdad Esfahbod 已提交
174
  inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
B
Behdad Esfahbod 已提交
175
    TRACE_SANITIZE (this);
176
    return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
B
WIP  
Behdad Esfahbod 已提交
177 178
  }

B
Behdad Esfahbod 已提交
179
  inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
B
Behdad Esfahbod 已提交
180
    TRACE_SANITIZE (this);
B
WIP  
Behdad Esfahbod 已提交
181 182
    unsigned int len = get_len ();

183
    if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
B
WIP  
Behdad Esfahbod 已提交
184

185
    if (!has_device ()) return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
186 187

    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
188
      if (!sanitize_value_devices (c, base, values))
189
        return TRACE_RETURN (false);
B
WIP  
Behdad Esfahbod 已提交
190 191 192
      values += len;
    }

193
    return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
194 195
  }

B
Behdad Esfahbod 已提交
196
  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
B
Behdad Esfahbod 已提交
197
  inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
B
Behdad Esfahbod 已提交
198
    TRACE_SANITIZE (this);
B
WIP  
Behdad Esfahbod 已提交
199

200
    if (!has_device ()) return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
201 202

    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
203
      if (!sanitize_value_devices (c, base, values))
204
        return TRACE_RETURN (false);
B
WIP  
Behdad Esfahbod 已提交
205 206 207
      values += stride;
    }

208
    return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
209
  }
B
Behdad Esfahbod 已提交
210 211 212
};


B
Behdad Esfahbod 已提交
213 214
struct AnchorFormat1
{
215
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
B
Behdad Esfahbod 已提交
216 217
			  hb_position_t *x, hb_position_t *y) const
  {
B
Minor  
Behdad Esfahbod 已提交
218 219
      *x = font->em_scale_x (xCoordinate);
      *y = font->em_scale_y (yCoordinate);
B
Behdad Esfahbod 已提交
220 221
  }

B
Behdad Esfahbod 已提交
222
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
223
    TRACE_SANITIZE (this);
224
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
225 226
  }

227
  protected:
B
Behdad Esfahbod 已提交
228 229 230
  USHORT	format;			/* Format identifier--format = 1 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
231 232
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
233 234
};

B
Behdad Esfahbod 已提交
235 236
struct AnchorFormat2
{
237
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
238 239
			  hb_position_t *x, hb_position_t *y) const
  {
240 241
      unsigned int x_ppem = font->x_ppem;
      unsigned int y_ppem = font->y_ppem;
B
Behdad Esfahbod 已提交
242
      hb_position_t cx, cy;
B
Behdad Esfahbod 已提交
243
      hb_bool_t ret = false;
B
Behdad Esfahbod 已提交
244 245

      if (x_ppem || y_ppem)
B
Behdad Esfahbod 已提交
246
	ret = font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
B
Minor  
Behdad Esfahbod 已提交
247 248
      *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
      *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
B
Behdad Esfahbod 已提交
249 250
  }

B
Behdad Esfahbod 已提交
251
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
252
    TRACE_SANITIZE (this);
253
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
254 255
  }

256
  protected:
B
Behdad Esfahbod 已提交
257 258 259 260
  USHORT	format;			/* Format identifier--format = 2 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
  USHORT	anchorPoint;		/* Index to glyph contour point */
261 262
  public:
  DEFINE_SIZE_STATIC (8);
B
Behdad Esfahbod 已提交
263 264
};

B
Behdad Esfahbod 已提交
265 266
struct AnchorFormat3
{
267
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
B
Behdad Esfahbod 已提交
268 269
			  hb_position_t *x, hb_position_t *y) const
  {
B
Minor  
Behdad Esfahbod 已提交
270 271
      *x = font->em_scale_x (xCoordinate);
      *y = font->em_scale_y (yCoordinate);
272

273 274 275 276
      if (font->x_ppem)
	*x += (this+xDeviceTable).get_x_delta (font);
      if (font->y_ppem)
	*y += (this+yDeviceTable).get_x_delta (font);
B
Behdad Esfahbod 已提交
277 278
  }

B
Behdad Esfahbod 已提交
279
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
280
    TRACE_SANITIZE (this);
281
    return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
B
Behdad Esfahbod 已提交
282 283
  }

284
  protected:
B
Behdad Esfahbod 已提交
285 286 287 288 289 290 291 292 293 294 295
  USHORT	format;			/* Format identifier--format = 3 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
  OffsetTo<Device>
		xDeviceTable;		/* Offset to Device table for X
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
  OffsetTo<Device>
		yDeviceTable;		/* Offset to Device table for Y
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
296 297
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
298 299
};

B
Behdad Esfahbod 已提交
300 301
struct Anchor
{
302
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
303 304
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
305 306
    *x = *y = 0;
    switch (u.format) {
307 308 309 310
    case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
    case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
    case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
    default:						 return;
B
Behdad Esfahbod 已提交
311 312 313
    }
  }

B
Behdad Esfahbod 已提交
314
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
315
    TRACE_SANITIZE (this);
316
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
317
    switch (u.format) {
318 319 320 321
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    case 2: return TRACE_RETURN (u.format2.sanitize (c));
    case 3: return TRACE_RETURN (u.format3.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
322 323 324
    }
  }

325
  protected:
B
Behdad Esfahbod 已提交
326 327
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
328 329 330
  AnchorFormat1		format1;
  AnchorFormat2		format2;
  AnchorFormat3		format3;
B
Behdad Esfahbod 已提交
331
  } u;
B
Behdad Esfahbod 已提交
332
  public:
B
Behdad Esfahbod 已提交
333
  DEFINE_SIZE_UNION (2, format);
B
Behdad Esfahbod 已提交
334 335 336
};


337 338
struct AnchorMatrix
{
339 340
  inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
    *found = false;
341
    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
342
    *found = !matrix[row * cols + col].is_null ();
343 344 345
    return this+matrix[row * cols + col];
  }

B
Behdad Esfahbod 已提交
346
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
B
Behdad Esfahbod 已提交
347
    TRACE_SANITIZE (this);
348 349
    if (!c->check_struct (this)) return TRACE_RETURN (false);
    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
350
    unsigned int count = rows * cols;
351
    if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
352
    for (unsigned int i = 0; i < count; i++)
353 354
      if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
    return TRACE_RETURN (true);
355 356 357
  }

  USHORT	rows;			/* Number of rows */
358
  protected:
359
  OffsetTo<Anchor>
B
Behdad Esfahbod 已提交
360
		matrix[VAR];		/* Matrix of offsets to Anchor tables--
361
					 * from beginning of AnchorMatrix table */
B
Behdad Esfahbod 已提交
362
  public:
363
  DEFINE_SIZE_ARRAY (2, matrix);
364 365 366
};


B
Behdad Esfahbod 已提交
367 368
struct MarkRecord
{
369
  friend struct MarkArray;
B
Behdad Esfahbod 已提交
370

B
Behdad Esfahbod 已提交
371
  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
B
Behdad Esfahbod 已提交
372
    TRACE_SANITIZE (this);
373
    return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
374 375
  }

376
  protected:
B
Behdad Esfahbod 已提交
377 378 379 380
  USHORT	klass;			/* Class defined for this mark */
  OffsetTo<Anchor>
		markAnchor;		/* Offset to Anchor table--from
					 * beginning of MarkArray table */
B
Behdad Esfahbod 已提交
381 382
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
383 384
};

B
Behdad Esfahbod 已提交
385
struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
B
Behdad Esfahbod 已提交
386
{
B
Behdad Esfahbod 已提交
387
  inline bool apply (hb_apply_context_t *c,
388 389 390 391
		     unsigned int mark_index, unsigned int glyph_index,
		     const AnchorMatrix &anchors, unsigned int class_count,
		     unsigned int glyph_pos) const
  {
B
Behdad Esfahbod 已提交
392
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
393
    const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
394 395 396
    unsigned int mark_class = record.klass;

    const Anchor& mark_anchor = this + record.markAnchor;
397 398 399 400 401
    bool found;
    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
    /* If this subtable doesn't have an anchor for this base and this class,
     * return false such that the subsequent subtables have a chance at it. */
    if (unlikely (!found)) return TRACE_RETURN (false);
402 403 404

    hb_position_t mark_x, mark_y, base_x, base_y;

405
    mark_anchor.get_anchor (c->font, c->buffer->cur().codepoint, &mark_x, &mark_y);
406
    glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
407

408
    hb_glyph_position_t &o = c->buffer->cur_pos();
B
Behdad Esfahbod 已提交
409 410
    o.x_offset = base_x - mark_x;
    o.y_offset = base_y - mark_y;
411
    o.attach_lookback() = c->buffer->idx - glyph_pos;
412

413
    c->buffer->idx++;
414
    return TRACE_RETURN (true);
415
  }
B
Behdad Esfahbod 已提交
416

B
Behdad Esfahbod 已提交
417
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
418
    TRACE_SANITIZE (this);
419
    return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
B
Behdad Esfahbod 已提交
420
  }
B
Behdad Esfahbod 已提交
421 422 423 424 425
};


/* Lookups */

B
Behdad Esfahbod 已提交
426 427
struct SinglePosFormat1
{
428 429 430
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
431
    (this+coverage).add_coverage (c->input);
432 433
  }

434 435 436 437 438
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
439
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
440
  {
B
Behdad Esfahbod 已提交
441
    TRACE_APPLY (this);
442
    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
443
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
444

445
    valueFormat.apply_value (c->font, c->direction, this,
446
			     values, c->buffer->cur_pos());
447

448
    c->buffer->idx++;
449
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
450 451
  }

B
Behdad Esfahbod 已提交
452
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
453
    TRACE_SANITIZE (this);
454
    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
B
Behdad Esfahbod 已提交
455 456
  }

457
  protected:
B
Behdad Esfahbod 已提交
458 459 460 461
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
462
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
463 464 465 466
					 * ValueRecord */
  ValueRecord	values;			/* Defines positioning
					 * value(s)--applied to all glyphs in
					 * the Coverage table */
B
Behdad Esfahbod 已提交
467
  public:
468
  DEFINE_SIZE_ARRAY (6, values);
B
Behdad Esfahbod 已提交
469 470
};

B
Behdad Esfahbod 已提交
471 472
struct SinglePosFormat2
{
473 474 475
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
476
    (this+coverage).add_coverage (c->input);
477 478
  }

479 480 481 482 483
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
484
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
485
  {
B
Behdad Esfahbod 已提交
486
    TRACE_APPLY (this);
487
    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
488
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
489

490
    if (likely (index >= valueCount)) return TRACE_RETURN (false);
491

492
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
493
			     &values[index * valueFormat.get_len ()],
494
			     c->buffer->cur_pos());
495

496
    c->buffer->idx++;
497
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
498 499
  }

B
Behdad Esfahbod 已提交
500
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
501
    TRACE_SANITIZE (this);
502
    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
B
Behdad Esfahbod 已提交
503 504
  }

505
  protected:
B
Behdad Esfahbod 已提交
506 507 508 509
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
510
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
511 512 513 514
					 * ValueRecord */
  USHORT	valueCount;		/* Number of ValueRecords */
  ValueRecord	values;			/* Array of ValueRecords--positioning
					 * values applied to glyphs */
B
Behdad Esfahbod 已提交
515
  public:
516
  DEFINE_SIZE_ARRAY (8, values);
B
Behdad Esfahbod 已提交
517 518
};

B
Behdad Esfahbod 已提交
519 520
struct SinglePos
{
521
  template <typename context_t>
522
  inline typename context_t::return_t dispatch (context_t *c) const
523
  {
524
    TRACE_DISPATCH (this);
525
    switch (u.format) {
526 527
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
B
Behdad Esfahbod 已提交
528
    default:return TRACE_RETURN (c->default_return_value ());
529 530 531
    }
  }

B
Behdad Esfahbod 已提交
532
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
533
    TRACE_SANITIZE (this);
534
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
535
    switch (u.format) {
536 537 538
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    case 2: return TRACE_RETURN (u.format2.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
539 540 541
    }
  }

542
  protected:
B
Behdad Esfahbod 已提交
543 544
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
545 546
  SinglePosFormat1	format1;
  SinglePosFormat2	format2;
B
Behdad Esfahbod 已提交
547 548 549 550
  } u;
};


B
Behdad Esfahbod 已提交
551 552
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
553
  friend struct PairSet;
B
Behdad Esfahbod 已提交
554

555
  protected:
B
Behdad Esfahbod 已提交
556 557 558 559 560
  GlyphID	secondGlyph;		/* GlyphID of second glyph in the
					 * pair--first glyph is listed in the
					 * Coverage table */
  ValueRecord	values;			/* Positioning data for the first glyph
					 * followed by for second glyph */
B
Behdad Esfahbod 已提交
561
  public:
562
  DEFINE_SIZE_ARRAY (2, values);
B
Behdad Esfahbod 已提交
563 564
};

B
Behdad Esfahbod 已提交
565 566
struct PairSet
{
B
Behdad Esfahbod 已提交
567 568
  friend struct PairPosFormat1;

569 570 571 572 573 574 575 576 577 578 579 580
  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
			      const ValueFormat *valueFormats) const
  {
    TRACE_COLLECT_GLYPHS (this);
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);

    const PairValueRecord *record = CastP<PairValueRecord> (array);
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
    {
B
Minor  
Behdad Esfahbod 已提交
581
      c->input->add (record->secondGlyph);
582 583 584 585
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }
  }

B
Behdad Esfahbod 已提交
586
  inline bool apply (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
587 588 589
		     const ValueFormat *valueFormats,
		     unsigned int pos) const
  {
B
Behdad Esfahbod 已提交
590
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
591 592 593 594 595
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);

    const PairValueRecord *record = CastP<PairValueRecord> (array);
596
    unsigned int count = len;
B
Behdad Esfahbod 已提交
597 598
    for (unsigned int i = 0; i < count; i++)
    {
599
      /* TODO bsearch */
600
      if (c->buffer->info[pos].codepoint == record->secondGlyph)
B
Behdad Esfahbod 已提交
601
      {
602
	valueFormats[0].apply_value (c->font, c->direction, this,
603
				     &record->values[0], c->buffer->cur_pos());
604 605
	valueFormats[1].apply_value (c->font, c->direction, this,
				     &record->values[len1], c->buffer->pos[pos]);
B
Behdad Esfahbod 已提交
606 607
	if (len2)
	  pos++;
608
	c->buffer->idx = pos;
609
	return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
610 611 612 613
      }
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }

614
    return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
615 616 617 618 619 620 621 622 623
  }

  struct sanitize_closure_t {
    void *base;
    ValueFormat *valueFormats;
    unsigned int len1; /* valueFormats[0].get_len() */
    unsigned int stride; /* 1 + len1 + len2 */
  };

B
Behdad Esfahbod 已提交
624
  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
B
Behdad Esfahbod 已提交
625
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
626
    if (!(c->check_struct (this)
627
       && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
628 629 630

    unsigned int count = len;
    PairValueRecord *record = CastP<PairValueRecord> (array);
631 632
    return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
		      && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
B
Behdad Esfahbod 已提交
633 634
  }

635
  protected:
B
Behdad Esfahbod 已提交
636
  USHORT	len;			/* Number of PairValueRecords */
637
  USHORT	array[VAR];		/* Array of PairValueRecords--ordered
B
Behdad Esfahbod 已提交
638
					 * by GlyphID of the second glyph */
B
Behdad Esfahbod 已提交
639
  public:
640
  DEFINE_SIZE_ARRAY (2, array);
B
Behdad Esfahbod 已提交
641
};
B
Behdad Esfahbod 已提交
642

B
Behdad Esfahbod 已提交
643 644
struct PairPosFormat1
{
645 646 647
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
648
    (this+coverage).add_coverage (c->input);
649 650 651 652 653
    unsigned int count = pairSet.len;
    for (unsigned int i = 0; i < count; i++)
      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
  }

654 655 656 657 658
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
659
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
660
  {
B
Behdad Esfahbod 已提交
661
    TRACE_APPLY (this);
662
    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
663
    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
664

665
    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
666
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
667

668
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
669

670
    return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
B
Behdad Esfahbod 已提交
671 672
  }

B
Behdad Esfahbod 已提交
673
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
674
    TRACE_SANITIZE (this);
675 676 677

    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
B
Behdad Esfahbod 已提交
678 679 680 681 682 683
    PairSet::sanitize_closure_t closure = {
      this,
      &valueFormat1,
      len1,
      1 + len1 + len2
    };
684

685
    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
B
Behdad Esfahbod 已提交
686 687
  }

688
  protected:
B
Behdad Esfahbod 已提交
689 690 691 692
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
693
  ValueFormat	valueFormat1;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
694 695
					 * ValueRecord1--for the first glyph
					 * in the pair--may be zero (0) */
696
  ValueFormat	valueFormat2;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
697 698 699 700 701
					 * ValueRecord2--for the second glyph
					 * in the pair--may be zero (0) */
  OffsetArrayOf<PairSet>
		pairSet;		/* Array of PairSet tables
					 * ordered by Coverage Index */
702
  public:
703
  DEFINE_SIZE_ARRAY (10, pairSet);
B
Behdad Esfahbod 已提交
704 705
};

B
Behdad Esfahbod 已提交
706 707
struct PairPosFormat2
{
708 709 710
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
711
    /* (this+coverage).add_coverage (c->input); // Don't need this. */
712 713 714 715

    unsigned int count1 = class1Count;
    const ClassDef &klass1 = this+classDef1;
    for (unsigned int i = 0; i < count1; i++)
B
Minor  
Behdad Esfahbod 已提交
716
      klass1.add_class (c->input, i);
717 718 719 720

    unsigned int count2 = class2Count;
    const ClassDef &klass2 = this+classDef2;
    for (unsigned int i = 0; i < count2; i++)
B
Minor  
Behdad Esfahbod 已提交
721
      klass2.add_class (c->input, i);
722 723
  }

724 725 726 727 728
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
729
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
730
  {
B
Behdad Esfahbod 已提交
731
    TRACE_APPLY (this);
732
    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
733
    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
734

735
    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
736
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
737

738
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
739 740 741 742 743

    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int record_len = len1 + len2;

744 745
    unsigned int klass1 = (this+classDef1).get_class (c->buffer->cur().codepoint);
    unsigned int klass2 = (this+classDef2).get_class (c->buffer->info[skippy_iter.idx].codepoint);
746
    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
747

B
Behdad Esfahbod 已提交
748
    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
749
    valueFormat1.apply_value (c->font, c->direction, this,
750
			      v, c->buffer->cur_pos());
751
    valueFormat2.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
752
			      v + len1, c->buffer->pos[skippy_iter.idx]);
B
Behdad Esfahbod 已提交
753

B
Behdad Esfahbod 已提交
754
    c->buffer->idx = skippy_iter.idx;
B
Behdad Esfahbod 已提交
755
    if (len2)
B
Behdad Esfahbod 已提交
756
      c->buffer->idx++;
B
Behdad Esfahbod 已提交
757

758
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
759 760
  }

B
Behdad Esfahbod 已提交
761
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
762
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
763 764 765
    if (!(c->check_struct (this)
       && coverage.sanitize (c, this)
       && classDef1.sanitize (c, this)
766
       && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
767

768 769 770
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int stride = len1 + len2;
B
Behdad Esfahbod 已提交
771
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
772
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
773 774 775
    return TRACE_RETURN (c->check_array (values, record_size, count) &&
			 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
			 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
B
Behdad Esfahbod 已提交
776
  }
B
Behdad Esfahbod 已提交
777

778
  protected:
B
Behdad Esfahbod 已提交
779 780 781 782
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
783
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
784 785
					 * first glyph of the pair--may be zero
					 * (0) */
786
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
					 * second glyph of the pair--may be
					 * zero (0) */
  OffsetTo<ClassDef>
		classDef1;		/* Offset to ClassDef table--from
					 * beginning of PairPos subtable--for
					 * the first glyph of the pair */
  OffsetTo<ClassDef>
		classDef2;		/* Offset to ClassDef table--from
					 * beginning of PairPos subtable--for
					 * the second glyph of the pair */
  USHORT	class1Count;		/* Number of classes in ClassDef1
					 * table--includes Class0 */
  USHORT	class2Count;		/* Number of classes in ClassDef2
					 * table--includes Class0 */
  ValueRecord	values;			/* Matrix of value pairs:
					 * class1-major, class2-minor,
					 * Each entry has value1 and value2 */
B
Behdad Esfahbod 已提交
804
  public:
805
  DEFINE_SIZE_ARRAY (16, values);
B
Behdad Esfahbod 已提交
806 807
};

B
Behdad Esfahbod 已提交
808 809
struct PairPos
{
810
  template <typename context_t>
811
  inline typename context_t::return_t dispatch (context_t *c) const
812
  {
813
    TRACE_DISPATCH (this);
814
    switch (u.format) {
815 816
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
B
Behdad Esfahbod 已提交
817
    default:return TRACE_RETURN (c->default_return_value ());
818 819 820
    }
  }

B
Behdad Esfahbod 已提交
821
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
822
    TRACE_SANITIZE (this);
823
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
824
    switch (u.format) {
825 826 827
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    case 2: return TRACE_RETURN (u.format2.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
828 829 830
    }
  }

831
  protected:
B
Behdad Esfahbod 已提交
832 833
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
834 835
  PairPosFormat1	format1;
  PairPosFormat2	format2;
B
Behdad Esfahbod 已提交
836 837 838 839
  } u;
};


B
Behdad Esfahbod 已提交
840 841
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
842 843
  friend struct CursivePosFormat1;

B
Behdad Esfahbod 已提交
844
  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
B
Behdad Esfahbod 已提交
845
    TRACE_SANITIZE (this);
846
    return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
847 848
  }

849
  protected:
B
Behdad Esfahbod 已提交
850 851 852 853 854 855 856 857
  OffsetTo<Anchor>
		entryAnchor;		/* Offset to EntryAnchor table--from
					 * beginning of CursivePos
					 * subtable--may be NULL */
  OffsetTo<Anchor>
		exitAnchor;		/* Offset to ExitAnchor table--from
					 * beginning of CursivePos
					 * subtable--may be NULL */
B
Behdad Esfahbod 已提交
858 859
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
860 861
};

B
Behdad Esfahbod 已提交
862 863
struct CursivePosFormat1
{
864 865 866
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
867
    (this+coverage).add_coverage (c->input);
868 869
  }

870 871 872 873 874
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
875
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
876
  {
B
Behdad Esfahbod 已提交
877
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
878 879

    /* We don't handle mark glyphs here. */
880
    if (c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
881

882
    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
883
    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
884

885
    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (c->buffer->cur().codepoint)];
886
    if (!this_record.exitAnchor) return TRACE_RETURN (false);
887

888
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
889

890
    const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (c->buffer->info[skippy_iter.idx].codepoint)];
891
    if (!next_record.entryAnchor) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
892

893
    unsigned int i = c->buffer->idx;
B
Behdad Esfahbod 已提交
894
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
895

896
    hb_position_t entry_x, entry_y, exit_x, exit_y;
897 898
    (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
    (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
B
Behdad Esfahbod 已提交
899

B
Behdad Esfahbod 已提交
900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
    hb_glyph_position_t *pos = c->buffer->pos;

    hb_position_t d;
    /* Main-direction adjustment */
    switch (c->direction) {
      case HB_DIRECTION_LTR:
	pos[i].x_advance  =  exit_x + pos[i].x_offset;

	d = entry_x + pos[j].x_offset;
	pos[j].x_advance -= d;
	pos[j].x_offset  -= d;
	break;
      case HB_DIRECTION_RTL:
	d = exit_x + pos[i].x_offset;
	pos[i].x_advance -= d;
	pos[i].x_offset  -= d;

	pos[j].x_advance  =  entry_x + pos[j].x_offset;
	break;
      case HB_DIRECTION_TTB:
	pos[i].y_advance  =  exit_y + pos[i].y_offset;

	d = entry_y + pos[j].y_offset;
	pos[j].y_advance -= d;
	pos[j].y_offset  -= d;
	break;
      case HB_DIRECTION_BTT:
	d = exit_y + pos[i].y_offset;
	pos[i].y_advance -= d;
	pos[i].y_offset  -= d;

	pos[j].y_advance  =  entry_y;
	break;
      case HB_DIRECTION_INVALID:
      default:
	break;
B
Behdad Esfahbod 已提交
936 937
    }

B
Behdad Esfahbod 已提交
938 939 940
    /* Cross-direction adjustment */
    if  (c->lookup_props & LookupFlag::RightToLeft) {
      pos[i].cursive_chain() = j - i;
941
      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
B
Behdad Esfahbod 已提交
942
	pos[i].y_offset = entry_y - exit_y;
943
      else
B
Behdad Esfahbod 已提交
944 945 946
	pos[i].x_offset = entry_x - exit_x;
    } else {
      pos[j].cursive_chain() = i - j;
947
      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
B
Behdad Esfahbod 已提交
948
	pos[j].y_offset = exit_y - entry_y;
949
      else
B
Behdad Esfahbod 已提交
950
	pos[j].x_offset = exit_x - entry_x;
B
Behdad Esfahbod 已提交
951 952
    }

953
    c->buffer->idx = j;
954
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
955 956
  }

B
Behdad Esfahbod 已提交
957
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
958
    TRACE_SANITIZE (this);
959
    return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
B
Behdad Esfahbod 已提交
960 961
  }

962
  protected:
B
Behdad Esfahbod 已提交
963 964 965 966 967 968 969
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
  ArrayOf<EntryExitRecord>
		entryExitRecord;	/* Array of EntryExit records--in
					 * Coverage Index order */
970
  public:
971
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
B
Behdad Esfahbod 已提交
972 973
};

B
Behdad Esfahbod 已提交
974 975
struct CursivePos
{
976
  template <typename context_t>
977
  inline typename context_t::return_t dispatch (context_t *c) const
978
  {
979
    TRACE_DISPATCH (this);
980
    switch (u.format) {
981
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
982
    default:return TRACE_RETURN (c->default_return_value ());
983 984 985
    }
  }

B
Behdad Esfahbod 已提交
986
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
987
    TRACE_SANITIZE (this);
988
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
989
    switch (u.format) {
990 991
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
992 993 994
    }
  }

995
  protected:
B
Behdad Esfahbod 已提交
996 997
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
998
  CursivePosFormat1	format1;
B
Behdad Esfahbod 已提交
999 1000 1001 1002
  } u;
};


1003 1004 1005
typedef AnchorMatrix BaseArray;		/* base-major--
					 * in order of BaseCoverage Index--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1006
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1007

B
Behdad Esfahbod 已提交
1008 1009
struct MarkBasePosFormat1
{
1010 1011 1012
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1013 1014
    (this+markCoverage).add_coverage (c->input);
    (this+baseCoverage).add_coverage (c->input);
1015 1016
  }

1017 1018 1019 1020 1021
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1022
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1023
  {
B
Behdad Esfahbod 已提交
1024
    TRACE_APPLY (this);
1025
    unsigned int mark_index = (this+markCoverage).get_coverage  (c->buffer->cur().codepoint);
1026
    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1027 1028

    /* now we search backwards for a non-mark glyph */
1029
    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
B
Behdad Esfahbod 已提交
1030
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1031
    do {
B
Behdad Esfahbod 已提交
1032
      if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1033 1034 1035 1036
      /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
      if (0 == get_lig_comp (c->buffer->info[skippy_iter.idx])) break;
      skippy_iter.reject ();
    } while (1);
1037

1038
    /* The following assertion is too strong, so we've disabled it. */
1039
    if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
B
Behdad Esfahbod 已提交
1040

1041
    unsigned int base_index = (this+baseCoverage).get_coverage  (c->buffer->info[skippy_iter.idx].codepoint);
1042
    if (base_index == NOT_COVERED) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1043

1044
    return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
B
Behdad Esfahbod 已提交
1045 1046
  }

B
Behdad Esfahbod 已提交
1047
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1048
    TRACE_SANITIZE (this);
1049 1050
    return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
			 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
B
Behdad Esfahbod 已提交
1051 1052
  }

1053
  protected:
B
Behdad Esfahbod 已提交
1054
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1055 1056
  OffsetTo<Coverage>
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
1057
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1058 1059
  OffsetTo<Coverage>
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
1060 1061
					 * beginning of MarkBasePos subtable */
  USHORT	classCount;		/* Number of classes defined for marks */
B
Behdad Esfahbod 已提交
1062 1063
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1064
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1065 1066
  OffsetTo<BaseArray>
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
1067
					 * beginning of MarkBasePos subtable */
1068 1069
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1070 1071
};

B
Behdad Esfahbod 已提交
1072 1073
struct MarkBasePos
{
1074
  template <typename context_t>
1075
  inline typename context_t::return_t dispatch (context_t *c) const
1076
  {
1077
    TRACE_DISPATCH (this);
1078
    switch (u.format) {
1079
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1080
    default:return TRACE_RETURN (c->default_return_value ());
1081 1082 1083
    }
  }

B
Behdad Esfahbod 已提交
1084
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1085
    TRACE_SANITIZE (this);
1086
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1087
    switch (u.format) {
1088 1089
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1090 1091 1092
    }
  }

1093
  protected:
B
Behdad Esfahbod 已提交
1094 1095
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1096
  MarkBasePosFormat1	format1;
B
Behdad Esfahbod 已提交
1097 1098 1099 1100
  } u;
};


1101 1102 1103
typedef AnchorMatrix LigatureAttach;	/* component-major--
					 * in order of writing direction--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1104
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1105

1106
typedef OffsetListOf<LigatureAttach> LigatureArray;
B
Behdad Esfahbod 已提交
1107
					/* Array of LigatureAttach
B
Behdad Esfahbod 已提交
1108 1109 1110
					 * tables ordered by
					 * LigatureCoverage Index */

B
Behdad Esfahbod 已提交
1111 1112
struct MarkLigPosFormat1
{
1113 1114 1115
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1116 1117
    (this+markCoverage).add_coverage (c->input);
    (this+ligatureCoverage).add_coverage (c->input);
1118 1119
  }

1120 1121 1122 1123 1124
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1125
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1126
  {
B
Behdad Esfahbod 已提交
1127
    TRACE_APPLY (this);
1128
    unsigned int mark_index = (this+markCoverage).get_coverage  (c->buffer->cur().codepoint);
1129
    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1130 1131

    /* now we search backwards for a non-mark glyph */
1132
    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
B
Behdad Esfahbod 已提交
1133 1134
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1135

1136
    /* The following assertion is too strong, so we've disabled it. */
1137
    if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
B
Behdad Esfahbod 已提交
1138

B
Behdad Esfahbod 已提交
1139
    unsigned int j = skippy_iter.idx;
1140
    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (c->buffer->info[j].codepoint);
1141
    if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1142 1143

    const LigatureArray& lig_array = this+ligatureArray;
1144
    const LigatureAttach& lig_attach = lig_array[lig_index];
1145 1146

    /* Find component to attach to */
B
Behdad Esfahbod 已提交
1147
    unsigned int comp_count = lig_attach.rows;
1148 1149
    if (unlikely (!comp_count)) return TRACE_RETURN (false);

B
Behdad Esfahbod 已提交
1150 1151 1152 1153
    /* We must now check whether the ligature ID of the current mark glyph
     * is identical to the ligature ID of the found ligature.  If yes, we
     * can directly use the component index.  If not, we attach the mark
     * glyph to the last component of the ligature. */
B
Behdad Esfahbod 已提交
1154 1155 1156 1157 1158 1159
    unsigned int comp_index;
    unsigned int lig_id = get_lig_id (c->buffer->info[j]);
    unsigned int mark_id = get_lig_id (c->buffer->cur());
    unsigned int mark_comp = get_lig_comp (c->buffer->cur());
    if (lig_id && lig_id == mark_id && mark_comp > 0)
      comp_index = MIN (comp_count, get_lig_comp (c->buffer->cur())) - 1;
B
Behdad Esfahbod 已提交
1160
    else
B
Behdad Esfahbod 已提交
1161
      comp_index = comp_count - 1;
B
Behdad Esfahbod 已提交
1162

1163
    return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
B
Behdad Esfahbod 已提交
1164 1165
  }

B
Behdad Esfahbod 已提交
1166
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1167
    TRACE_SANITIZE (this);
1168 1169
    return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
			 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
B
Behdad Esfahbod 已提交
1170 1171
  }

1172
  protected:
B
Behdad Esfahbod 已提交
1173
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1174 1175
  OffsetTo<Coverage>
		markCoverage;		/* Offset to Mark Coverage table--from
B
Behdad Esfahbod 已提交
1176
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1177 1178
  OffsetTo<Coverage>
		ligatureCoverage;	/* Offset to Ligature Coverage
B
Behdad Esfahbod 已提交
1179 1180 1181
					 * table--from beginning of MarkLigPos
					 * subtable */
  USHORT	classCount;		/* Number of defined mark classes */
B
Behdad Esfahbod 已提交
1182 1183
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1184
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1185 1186
  OffsetTo<LigatureArray>
		ligatureArray;		/* Offset to LigatureArray table--from
B
Behdad Esfahbod 已提交
1187
					 * beginning of MarkLigPos subtable */
1188 1189
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1190 1191
};

B
Behdad Esfahbod 已提交
1192 1193
struct MarkLigPos
{
1194
  template <typename context_t>
1195
  inline typename context_t::return_t dispatch (context_t *c) const
1196
  {
1197
    TRACE_DISPATCH (this);
1198
    switch (u.format) {
1199
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1200
    default:return TRACE_RETURN (c->default_return_value ());
1201 1202 1203
    }
  }

B
Behdad Esfahbod 已提交
1204
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1205
    TRACE_SANITIZE (this);
1206
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1207
    switch (u.format) {
1208 1209
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1210 1211 1212
    }
  }

1213
  protected:
B
Behdad Esfahbod 已提交
1214 1215
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1216
  MarkLigPosFormat1	format1;
B
Behdad Esfahbod 已提交
1217 1218 1219 1220
  } u;
};


1221 1222 1223 1224
typedef AnchorMatrix Mark2Array;	/* mark2-major--
					 * in order of Mark2Coverage Index--,
					 * mark1-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1225

B
Behdad Esfahbod 已提交
1226 1227
struct MarkMarkPosFormat1
{
1228 1229 1230
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1231 1232
    (this+mark1Coverage).add_coverage (c->input);
    (this+mark2Coverage).add_coverage (c->input);
1233 1234
  }

1235 1236 1237 1238 1239
  inline const Coverage &get_coverage (void) const
  {
    return this+mark1Coverage;
  }

B
Behdad Esfahbod 已提交
1240
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1241
  {
B
Behdad Esfahbod 已提交
1242
    TRACE_APPLY (this);
1243
    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (c->buffer->cur().codepoint);
1244
    if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1245 1246

    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1247
    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
B
Behdad Esfahbod 已提交
1248 1249
    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1250

1251
    if (!(c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) { return TRACE_RETURN (false); }
B
Behdad Esfahbod 已提交
1252

B
Behdad Esfahbod 已提交
1253 1254
    unsigned int j = skippy_iter.idx;

1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
    unsigned int id1 = get_lig_id (c->buffer->cur());
    unsigned int id2 = get_lig_id (c->buffer->info[j]);
    unsigned int comp1 = get_lig_comp (c->buffer->cur());
    unsigned int comp2 = get_lig_comp (c->buffer->info[j]);

    if (likely (id1 == id2)) {
      if (id1 == 0) /* Marks belonging to the same base. */
	goto good;
      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
        goto good;
    } else {
      /* If ligature ids don't match, it may be the case that one of the marks
       * itself is a ligature.  In which case match. */
      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
	goto good;
    }

    /* Didn't match. */
    return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1274

1275
    good:
1276
    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (c->buffer->info[j].codepoint);
1277
    if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1278

1279
    return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
B
Behdad Esfahbod 已提交
1280 1281
  }

B
Behdad Esfahbod 已提交
1282
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1283
    TRACE_SANITIZE (this);
1284 1285 1286
    return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
			 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
			 && mark2Array.sanitize (c, this, (unsigned int) classCount));
B
Behdad Esfahbod 已提交
1287 1288
  }

1289
  protected:
B
Behdad Esfahbod 已提交
1290
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1291 1292
  OffsetTo<Coverage>
		mark1Coverage;		/* Offset to Combining Mark1 Coverage
B
Behdad Esfahbod 已提交
1293 1294
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1295 1296
  OffsetTo<Coverage>
		mark2Coverage;		/* Offset to Combining Mark2 Coverage
B
Behdad Esfahbod 已提交
1297 1298
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1299 1300 1301 1302 1303 1304 1305
  USHORT	classCount;		/* Number of defined mark classes */
  OffsetTo<MarkArray>
		mark1Array;		/* Offset to Mark1Array table--from
					 * beginning of MarkMarkPos subtable */
  OffsetTo<Mark2Array>
		mark2Array;		/* Offset to Mark2Array table--from
					 * beginning of MarkMarkPos subtable */
1306 1307
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1308 1309
};

B
Behdad Esfahbod 已提交
1310 1311
struct MarkMarkPos
{
1312
  template <typename context_t>
1313
  inline typename context_t::return_t dispatch (context_t *c) const
1314
  {
1315
    TRACE_DISPATCH (this);
1316
    switch (u.format) {
1317
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1318
    default:return TRACE_RETURN (c->default_return_value ());
1319 1320 1321
    }
  }

B
Behdad Esfahbod 已提交
1322
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1323
    TRACE_SANITIZE (this);
1324
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1325
    switch (u.format) {
1326 1327
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1328 1329 1330
    }
  }

1331
  protected:
B
Behdad Esfahbod 已提交
1332 1333
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1334
  MarkMarkPosFormat1	format1;
B
Behdad Esfahbod 已提交
1335 1336 1337 1338
  } u;
};


B
Minor  
Behdad Esfahbod 已提交
1339
struct ContextPos : Context {};
B
Behdad Esfahbod 已提交
1340

B
Minor  
Behdad Esfahbod 已提交
1341
struct ChainContextPos : ChainContext {};
B
Behdad Esfahbod 已提交
1342

B
Behdad Esfahbod 已提交
1343
struct ExtensionPos : Extension<ExtensionPos>
B
Behdad Esfahbod 已提交
1344
{
1345
  typedef struct PosLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
1346 1347 1348
};


1349

B
Behdad Esfahbod 已提交
1350 1351 1352 1353 1354
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
1355 1356
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
1357 1358
  friend struct PosLookup;

B
Behdad Esfahbod 已提交
1359
  enum Type {
1360 1361 1362 1363 1364 1365 1366 1367
    Single		= 1,
    Pair		= 2,
    Cursive		= 3,
    MarkBase		= 4,
    MarkLig		= 5,
    MarkMark		= 6,
    Context		= 7,
    ChainContext	= 8,
1368
    Extension		= 9
1369 1370
  };

1371
  template <typename context_t>
1372
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1373
  {
1374
    TRACE_DISPATCH (this);
1375
    switch (lookup_type) {
1376 1377 1378 1379 1380 1381 1382 1383 1384
    case Single:		return TRACE_RETURN (u.single.dispatch (c));
    case Pair:			return TRACE_RETURN (u.pair.dispatch (c));
    case Cursive:		return TRACE_RETURN (u.cursive.dispatch (c));
    case MarkBase:		return TRACE_RETURN (u.markBase.dispatch (c));
    case MarkLig:		return TRACE_RETURN (u.markLig.dispatch (c));
    case MarkMark:		return TRACE_RETURN (u.markMark.dispatch (c));
    case Context:		return TRACE_RETURN (u.context.dispatch (c));
    case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
    case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
B
Behdad Esfahbod 已提交
1385
    default:			return TRACE_RETURN (c->default_return_value ());
1386
    }
1387 1388
  }

B
Behdad Esfahbod 已提交
1389
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
B
Behdad Esfahbod 已提交
1390
    TRACE_SANITIZE (this);
1391
    if (!u.header.sub_format.sanitize (c))
1392
      return TRACE_RETURN (false);
1393
    switch (lookup_type) {
1394 1395 1396 1397 1398 1399
    case Single:		return TRACE_RETURN (u.single.sanitize (c));
    case Pair:			return TRACE_RETURN (u.pair.sanitize (c));
    case Cursive:		return TRACE_RETURN (u.cursive.sanitize (c));
    case MarkBase:		return TRACE_RETURN (u.markBase.sanitize (c));
    case MarkLig:		return TRACE_RETURN (u.markLig.sanitize (c));
    case MarkMark:		return TRACE_RETURN (u.markMark.sanitize (c));
1400
    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1401 1402 1403
    case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
    case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
    default:			return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1404 1405 1406
    }
  }

1407
  protected:
B
Behdad Esfahbod 已提交
1408
  union {
B
Behdad Esfahbod 已提交
1409
  struct {
1410
    USHORT		sub_format;
B
Behdad Esfahbod 已提交
1411
  } header;
B
Behdad Esfahbod 已提交
1412 1413 1414 1415 1416 1417
  SinglePos		single;
  PairPos		pair;
  CursivePos		cursive;
  MarkBasePos		markBase;
  MarkLigPos		markLig;
  MarkMarkPos		markMark;
1418
  ContextPos		context;
B
Behdad Esfahbod 已提交
1419 1420
  ChainContextPos	chainContext;
  ExtensionPos		extension;
B
Behdad Esfahbod 已提交
1421
  } u;
B
Behdad Esfahbod 已提交
1422
  public:
B
Behdad Esfahbod 已提交
1423
  DEFINE_SIZE_UNION (2, header.sub_format);
B
Behdad Esfahbod 已提交
1424 1425 1426
};


B
Behdad Esfahbod 已提交
1427 1428
struct PosLookup : Lookup
{
1429 1430
  inline const PosLookupSubTable& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
B
Behdad Esfahbod 已提交
1431

B
Behdad Esfahbod 已提交
1432 1433 1434 1435 1436
  inline bool is_reverse (void) const
  {
    return false;
  }

1437 1438 1439 1440 1441 1442
  inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
  {
    TRACE_IS_INPLACE (this);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
1443
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1444 1445
  {
    TRACE_COLLECT_GLYPHS (this);
1446
    c->set_recurse_func (NULL);
1447
    return TRACE_RETURN (dispatch (c));
1448 1449
  }

B
Behdad Esfahbod 已提交
1450 1451 1452
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1453
    hb_get_coverage_context_t c;
B
Behdad Esfahbod 已提交
1454 1455 1456
    const Coverage *last = NULL;
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
1457
      const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
1458 1459 1460
      if (coverage != last) {
        coverage->add_coverage (glyphs);
        last = coverage;
B
Behdad Esfahbod 已提交
1461 1462 1463 1464
      }
    }
  }

1465
  inline bool apply_once (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1466
  {
B
Behdad Esfahbod 已提交
1467
    TRACE_APPLY (this);
1468
    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
B
Behdad Esfahbod 已提交
1469
      return TRACE_RETURN (false);
1470
    return TRACE_RETURN (dispatch (c));
B
Behdad Esfahbod 已提交
1471 1472
  }

1473 1474
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);

B
Behdad Esfahbod 已提交
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491
  template <typename context_t>
  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);

  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    unsigned int lookup_type = get_type ();
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
      typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
      if (c->stop_sublookup_iteration (r))
        return TRACE_RETURN (r);
    }
    return TRACE_RETURN (c->default_return_value ());
  }

B
Behdad Esfahbod 已提交
1492
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1493
    TRACE_SANITIZE (this);
1494
    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1495
    OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1496
    return TRACE_RETURN (list.sanitize (c, this, get_type ()));
B
Behdad Esfahbod 已提交
1497
  }
B
Behdad Esfahbod 已提交
1498 1499
};

B
Behdad Esfahbod 已提交
1500
typedef OffsetListOf<PosLookup> PosLookupList;
B
Behdad Esfahbod 已提交
1501 1502

/*
B
Behdad Esfahbod 已提交
1503
 * GPOS -- The Glyph Positioning Table
B
Behdad Esfahbod 已提交
1504 1505
 */

B
Behdad Esfahbod 已提交
1506 1507
struct GPOS : GSUBGPOS
{
B
Behdad Esfahbod 已提交
1508
  static const hb_tag_t Tag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1509

B
Behdad Esfahbod 已提交
1510
  inline const PosLookup& get_lookup (unsigned int i) const
1511
  { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
B
Behdad Esfahbod 已提交
1512

1513
  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1514
  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
B
Behdad Esfahbod 已提交
1515

B
Behdad Esfahbod 已提交
1516
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1517
    TRACE_SANITIZE (this);
1518
    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1519
    OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1520
    return TRACE_RETURN (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1521
  }
1522 1523
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
1524 1525
};

B
Behdad Esfahbod 已提交
1526 1527 1528 1529

static void
fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
{
B
Behdad Esfahbod 已提交
1530 1531 1532
  unsigned int j = pos[i].cursive_chain();
  if (likely (!j))
    return;
B
Behdad Esfahbod 已提交
1533

B
Behdad Esfahbod 已提交
1534
  j += i;
B
Behdad Esfahbod 已提交
1535

B
Behdad Esfahbod 已提交
1536
  pos[i].cursive_chain() = 0;
B
Behdad Esfahbod 已提交
1537

B
Behdad Esfahbod 已提交
1538
  fix_cursive_minor_offset (pos, j, direction);
B
Behdad Esfahbod 已提交
1539

B
Behdad Esfahbod 已提交
1540 1541 1542 1543
  if (HB_DIRECTION_IS_HORIZONTAL (direction))
    pos[i].y_offset += pos[j].y_offset;
  else
    pos[i].x_offset += pos[j].x_offset;
B
Behdad Esfahbod 已提交
1544 1545 1546
}

static void
1547
fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
B
Behdad Esfahbod 已提交
1548 1549 1550 1551 1552 1553 1554 1555 1556 1557
{
  if (likely (!(pos[i].attach_lookback())))
    return;

  unsigned int j = i - pos[i].attach_lookback();

  pos[i].x_offset += pos[j].x_offset;
  pos[i].y_offset += pos[j].y_offset;

  if (HB_DIRECTION_IS_FORWARD (direction))
1558
    for (unsigned int k = j; k < i; k++) {
B
Behdad Esfahbod 已提交
1559 1560 1561 1562
      pos[i].x_offset -= pos[k].x_advance;
      pos[i].y_offset -= pos[k].y_advance;
    }
  else
1563
    for (unsigned int k = j + 1; k < i + 1; k++) {
B
Behdad Esfahbod 已提交
1564 1565 1566 1567 1568
      pos[i].x_offset += pos[k].x_advance;
      pos[i].y_offset += pos[k].y_advance;
    }
}

B
Behdad Esfahbod 已提交
1569
void
1570
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1571 1572
{
  buffer->clear_positions ();
1573 1574 1575 1576

  unsigned int count = buffer->len;
  for (unsigned int i = 0; i < count; i++)
    buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
B
Behdad Esfahbod 已提交
1577 1578
}

B
Behdad Esfahbod 已提交
1579
void
1580
GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1581
{
1582 1583
  unsigned int len;
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
B
Behdad Esfahbod 已提交
1584 1585
  hb_direction_t direction = buffer->props.direction;

B
Behdad Esfahbod 已提交
1586 1587 1588
  /* Handle cursive connections */
  for (unsigned int i = 0; i < len; i++)
    fix_cursive_minor_offset (pos, i, direction);
B
Behdad Esfahbod 已提交
1589 1590

  /* Handle attachments */
B
Behdad Esfahbod 已提交
1591
  for (unsigned int i = 0; i < len; i++)
1592
    fix_mark_attachment (pos, i, direction);
1593

1594
  HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
1595
  HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
B
Minor  
Behdad Esfahbod 已提交
1596
  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
B
Behdad Esfahbod 已提交
1597 1598
}

B
Behdad Esfahbod 已提交
1599 1600 1601

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

1602
template <typename context_t>
1603
inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1604 1605 1606
{
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
  const PosLookup &l = gpos.get_lookup (lookup_index);
1607
  return l.dispatch (c);
1608 1609
}

1610
inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1611
{
1612
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
B
Behdad Esfahbod 已提交
1613
  const PosLookup &l = gpos.get_lookup (lookup_index);
1614
  unsigned int saved_lookup_props = c->lookup_props;
1615
  c->set_lookup (l);
1616 1617 1618
  bool ret = l.apply_once (c);
  c->lookup_props = saved_lookup_props;
  return ret;
B
Behdad Esfahbod 已提交
1619 1620 1621
}


B
Behdad Esfahbod 已提交
1622 1623 1624 1625
#undef attach_lookback
#undef cursive_chain


B
Behdad Esfahbod 已提交
1626
} /* namespace OT */
1627

B
Behdad Esfahbod 已提交
1628

1629
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */