hb-ot-layout-gpos-table.hh 51.4 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
B
Behdad Esfahbod 已提交
3
 * Copyright © 2010,2012  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 339
struct AnchorMatrix
{
  inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
340
    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
341 342 343
    return this+matrix[row * cols + col];
  }

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

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


B
Behdad Esfahbod 已提交
365 366
struct MarkRecord
{
367
  friend struct MarkArray;
B
Behdad Esfahbod 已提交
368

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

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

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

    const Anchor& mark_anchor = this + record.markAnchor;
    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);

    hb_position_t mark_x, mark_y, base_x, base_y;

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

402
    hb_glyph_position_t &o = c->buffer->cur_pos();
B
Behdad Esfahbod 已提交
403 404
    o.x_offset = base_x - mark_x;
    o.y_offset = base_y - mark_y;
405
    o.attach_lookback() = c->buffer->idx - glyph_pos;
406

407
    c->buffer->idx++;
408
    return TRACE_RETURN (true);
409
  }
B
Behdad Esfahbod 已提交
410

B
Behdad Esfahbod 已提交
411
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
412
    TRACE_SANITIZE (this);
413
    return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
B
Behdad Esfahbod 已提交
414
  }
B
Behdad Esfahbod 已提交
415 416 417 418 419
};


/* Lookups */

B
Behdad Esfahbod 已提交
420 421
struct SinglePosFormat1
{
422 423 424
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
425
    (this+coverage).add_coverage (c->input);
426 427
  }

428 429 430 431 432
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
433
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
434
  {
B
Behdad Esfahbod 已提交
435
    TRACE_APPLY (this);
436
    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
437
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
438

439
    valueFormat.apply_value (c->font, c->direction, this,
440
			     values, c->buffer->cur_pos());
441

442
    c->buffer->idx++;
443
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
444 445
  }

B
Behdad Esfahbod 已提交
446
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
447
    TRACE_SANITIZE (this);
448
    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
B
Behdad Esfahbod 已提交
449 450
  }

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

B
Behdad Esfahbod 已提交
465 466
struct SinglePosFormat2
{
467 468 469
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
470
    (this+coverage).add_coverage (c->input);
471 472
  }

473 474 475 476 477
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
478
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
479
  {
B
Behdad Esfahbod 已提交
480
    TRACE_APPLY (this);
481
    unsigned int index = (this+coverage).get_coverage  (c->buffer->cur().codepoint);
482
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
483

484
    if (likely (index >= valueCount)) return TRACE_RETURN (false);
485

486
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
487
			     &values[index * valueFormat.get_len ()],
488
			     c->buffer->cur_pos());
489

490
    c->buffer->idx++;
491
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
492 493
  }

B
Behdad Esfahbod 已提交
494
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
495
    TRACE_SANITIZE (this);
496
    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
B
Behdad Esfahbod 已提交
497 498
  }

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

B
Behdad Esfahbod 已提交
513 514
struct SinglePos
{
515 516
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
517
  {
B
Behdad Esfahbod 已提交
518
    TRACE_PROCESS (this);
519
    switch (u.format) {
B
Behdad Esfahbod 已提交
520 521 522
    case 1: return TRACE_RETURN (c->process (u.format1));
    case 2: return TRACE_RETURN (c->process (u.format2));
    default:return TRACE_RETURN (c->default_return_value ());
523 524 525
    }
  }

B
Behdad Esfahbod 已提交
526
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
527
    TRACE_SANITIZE (this);
528
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
529
    switch (u.format) {
530 531 532
    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 已提交
533 534 535
    }
  }

536
  protected:
B
Behdad Esfahbod 已提交
537 538
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
539 540
  SinglePosFormat1	format1;
  SinglePosFormat2	format2;
B
Behdad Esfahbod 已提交
541 542 543 544
  } u;
};


B
Behdad Esfahbod 已提交
545 546
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
547
  friend struct PairSet;
B
Behdad Esfahbod 已提交
548

549
  protected:
B
Behdad Esfahbod 已提交
550 551 552 553 554
  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 已提交
555
  public:
556
  DEFINE_SIZE_ARRAY (2, values);
B
Behdad Esfahbod 已提交
557 558
};

B
Behdad Esfahbod 已提交
559 560
struct PairSet
{
B
Behdad Esfahbod 已提交
561 562
  friend struct PairPosFormat1;

563 564 565 566 567 568 569 570 571 572 573 574
  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 已提交
575
      c->input->add (record->secondGlyph);
576 577 578 579
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }
  }

B
Behdad Esfahbod 已提交
580
  inline bool apply (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
581 582 583
		     const ValueFormat *valueFormats,
		     unsigned int pos) const
  {
B
Behdad Esfahbod 已提交
584
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
585 586 587 588 589
    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);
590
    unsigned int count = len;
B
Behdad Esfahbod 已提交
591 592
    for (unsigned int i = 0; i < count; i++)
    {
593
      if (c->buffer->info[pos].codepoint == record->secondGlyph)
B
Behdad Esfahbod 已提交
594
      {
595
	valueFormats[0].apply_value (c->font, c->direction, this,
596
				     &record->values[0], c->buffer->cur_pos());
597 598
	valueFormats[1].apply_value (c->font, c->direction, this,
				     &record->values[len1], c->buffer->pos[pos]);
B
Behdad Esfahbod 已提交
599 600
	if (len2)
	  pos++;
601
	c->buffer->idx = pos;
602
	return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
603 604 605 606
      }
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }

607
    return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
608 609 610 611 612 613 614 615 616
  }

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

B
Behdad Esfahbod 已提交
617
  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
B
Behdad Esfahbod 已提交
618
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
619
    if (!(c->check_struct (this)
620
       && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
621 622 623

    unsigned int count = len;
    PairValueRecord *record = CastP<PairValueRecord> (array);
624 625
    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 已提交
626 627
  }

628
  protected:
B
Behdad Esfahbod 已提交
629
  USHORT	len;			/* Number of PairValueRecords */
630
  USHORT	array[VAR];		/* Array of PairValueRecords--ordered
B
Behdad Esfahbod 已提交
631
					 * by GlyphID of the second glyph */
B
Behdad Esfahbod 已提交
632
  public:
633
  DEFINE_SIZE_ARRAY (2, array);
B
Behdad Esfahbod 已提交
634
};
B
Behdad Esfahbod 已提交
635

B
Behdad Esfahbod 已提交
636 637
struct PairPosFormat1
{
638 639 640
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
641
    (this+coverage).add_coverage (c->input);
642 643 644 645 646
    unsigned int count = pairSet.len;
    for (unsigned int i = 0; i < count; i++)
      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
  }

647 648 649 650 651
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
652
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
653
  {
B
Behdad Esfahbod 已提交
654
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
655
    hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
656
    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
657

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

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

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

B
Behdad Esfahbod 已提交
666
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
667
    TRACE_SANITIZE (this);
668 669 670

    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
B
Behdad Esfahbod 已提交
671 672 673 674 675 676
    PairSet::sanitize_closure_t closure = {
      this,
      &valueFormat1,
      len1,
      1 + len1 + len2
    };
677

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

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

B
Behdad Esfahbod 已提交
699 700
struct PairPosFormat2
{
701 702 703
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
704
    /* (this+coverage).add_coverage (c->input); // Don't need this. */
705 706 707 708 709 710

    /* TODO only add values for pairs that have nonzero adjustments. */

    unsigned int count1 = class1Count;
    const ClassDef &klass1 = this+classDef1;
    for (unsigned int i = 0; i < count1; i++)
B
Minor  
Behdad Esfahbod 已提交
711
      klass1.add_class (c->input, i);
712 713 714 715

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

719 720 721 722 723
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
724
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
725
  {
B
Behdad Esfahbod 已提交
726
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
727
    hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
728
    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
729

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

733
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
734 735 736 737 738

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

739 740
    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);
741
    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
742

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

B
Behdad Esfahbod 已提交
749
    c->buffer->idx = skippy_iter.idx;
B
Behdad Esfahbod 已提交
750
    if (len2)
B
Behdad Esfahbod 已提交
751
      c->buffer->idx++;
B
Behdad Esfahbod 已提交
752

753
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
754 755
  }

B
Behdad Esfahbod 已提交
756
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
757
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
758 759 760
    if (!(c->check_struct (this)
       && coverage.sanitize (c, this)
       && classDef1.sanitize (c, this)
761
       && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
762

763 764 765
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int stride = len1 + len2;
B
Behdad Esfahbod 已提交
766
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
767
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
768 769 770
    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 已提交
771
  }
B
Behdad Esfahbod 已提交
772

773
  protected:
B
Behdad Esfahbod 已提交
774 775 776 777
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
778
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
779 780
					 * first glyph of the pair--may be zero
					 * (0) */
781
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
					 * 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 已提交
799
  public:
800
  DEFINE_SIZE_ARRAY (16, values);
B
Behdad Esfahbod 已提交
801 802
};

B
Behdad Esfahbod 已提交
803 804
struct PairPos
{
805 806
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
807
  {
B
Behdad Esfahbod 已提交
808
    TRACE_PROCESS (this);
809
    switch (u.format) {
B
Behdad Esfahbod 已提交
810 811 812
    case 1: return TRACE_RETURN (c->process (u.format1));
    case 2: return TRACE_RETURN (c->process (u.format2));
    default:return TRACE_RETURN (c->default_return_value ());
813 814 815
    }
  }

B
Behdad Esfahbod 已提交
816
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
817
    TRACE_SANITIZE (this);
818
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
819
    switch (u.format) {
820 821 822
    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 已提交
823 824 825
    }
  }

826
  protected:
B
Behdad Esfahbod 已提交
827 828
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
829 830
  PairPosFormat1	format1;
  PairPosFormat2	format2;
B
Behdad Esfahbod 已提交
831 832 833 834
  } u;
};


B
Behdad Esfahbod 已提交
835 836
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
837 838
  friend struct CursivePosFormat1;

B
Behdad Esfahbod 已提交
839
  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
B
Behdad Esfahbod 已提交
840
    TRACE_SANITIZE (this);
841
    return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
842 843
  }

844
  protected:
B
Behdad Esfahbod 已提交
845 846 847 848 849 850 851 852
  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 已提交
853 854
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
855 856
};

B
Behdad Esfahbod 已提交
857 858
struct CursivePosFormat1
{
859 860 861
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
862
    (this+coverage).add_coverage (c->input);
863 864
  }

865 866 867 868 869
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
870
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
871
  {
B
Behdad Esfahbod 已提交
872
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
873 874

    /* We don't handle mark glyphs here. */
875
    if (c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
876

B
Behdad Esfahbod 已提交
877
    hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
878
    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
879

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

883
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
884

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

888
    unsigned int i = c->buffer->idx;
B
Behdad Esfahbod 已提交
889
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
890

891
    hb_position_t entry_x, entry_y, exit_x, exit_y;
892 893
    (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 已提交
894

B
Behdad Esfahbod 已提交
895 896 897 898 899 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
    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 已提交
931 932
    }

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

948
    c->buffer->idx = j;
949
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
950 951
  }

B
Behdad Esfahbod 已提交
952
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
953
    TRACE_SANITIZE (this);
954
    return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
B
Behdad Esfahbod 已提交
955 956
  }

957
  protected:
B
Behdad Esfahbod 已提交
958 959 960 961 962 963 964
  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 */
965
  public:
966
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
B
Behdad Esfahbod 已提交
967 968
};

B
Behdad Esfahbod 已提交
969 970
struct CursivePos
{
971 972
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
973
  {
B
Behdad Esfahbod 已提交
974
    TRACE_PROCESS (this);
975
    switch (u.format) {
B
Behdad Esfahbod 已提交
976 977
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
978 979 980
    }
  }

B
Behdad Esfahbod 已提交
981
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
982
    TRACE_SANITIZE (this);
983
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
984
    switch (u.format) {
985 986
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
987 988 989
    }
  }

990
  protected:
B
Behdad Esfahbod 已提交
991 992
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
993
  CursivePosFormat1	format1;
B
Behdad Esfahbod 已提交
994 995 996 997
  } u;
};


998 999 1000
typedef AnchorMatrix BaseArray;		/* base-major--
					 * in order of BaseCoverage Index--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1001
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1002

B
Behdad Esfahbod 已提交
1003 1004
struct MarkBasePosFormat1
{
1005 1006 1007
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1008 1009
    (this+markCoverage).add_coverage (c->input);
    (this+baseCoverage).add_coverage (c->input);
1010 1011 1012
    /* TODO only add combinations that have nonzero adjustment. */
  }

1013 1014 1015 1016 1017
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

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

    /* now we search backwards for a non-mark glyph */
1025
    unsigned int property;
B
Behdad Esfahbod 已提交
1026
    hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1027 1028 1029 1030 1031 1032
    do {
      if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
      /* 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);
1033

1034
    /* The following assertion is too strong, so we've disabled it. */
1035
    if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH)) {/*return TRACE_RETURN (false);*/}
B
Behdad Esfahbod 已提交
1036

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

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

B
Behdad Esfahbod 已提交
1043
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1044
    TRACE_SANITIZE (this);
1045 1046
    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 已提交
1047 1048
  }

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

B
Behdad Esfahbod 已提交
1068 1069
struct MarkBasePos
{
1070 1071
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
1072
  {
B
Behdad Esfahbod 已提交
1073
    TRACE_PROCESS (this);
1074
    switch (u.format) {
B
Behdad Esfahbod 已提交
1075 1076
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
1077 1078 1079
    }
  }

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

1089
  protected:
B
Behdad Esfahbod 已提交
1090 1091
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1092
  MarkBasePosFormat1	format1;
B
Behdad Esfahbod 已提交
1093 1094 1095 1096
  } u;
};


1097 1098 1099
typedef AnchorMatrix LigatureAttach;	/* component-major--
					 * in order of writing direction--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1100
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1101

1102
typedef OffsetListOf<LigatureAttach> LigatureArray;
B
Behdad Esfahbod 已提交
1103
					/* Array of LigatureAttach
B
Behdad Esfahbod 已提交
1104 1105 1106
					 * tables ordered by
					 * LigatureCoverage Index */

B
Behdad Esfahbod 已提交
1107 1108
struct MarkLigPosFormat1
{
1109 1110 1111
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1112 1113
    (this+markCoverage).add_coverage (c->input);
    (this+ligatureCoverage).add_coverage (c->input);
1114 1115 1116
    /* TODO only add combinations that have nonzero adjustment. */
  }

1117 1118 1119 1120 1121
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

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

    /* now we search backwards for a non-mark glyph */
1129
    unsigned int property;
B
Behdad Esfahbod 已提交
1130
    hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1131
    if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks)) return TRACE_RETURN (false);
1132

1133
    /* The following assertion is too strong, so we've disabled it. */
1134
    if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE)) {/*return TRACE_RETURN (false);*/}
B
Behdad Esfahbod 已提交
1135

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

    const LigatureArray& lig_array = this+ligatureArray;
1141
    const LigatureAttach& lig_attach = lig_array[lig_index];
1142 1143

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

B
Behdad Esfahbod 已提交
1147 1148 1149 1150
    /* 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 已提交
1151 1152 1153 1154 1155 1156
    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 已提交
1157
    else
B
Behdad Esfahbod 已提交
1158
      comp_index = comp_count - 1;
B
Behdad Esfahbod 已提交
1159

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

B
Behdad Esfahbod 已提交
1163
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1164
    TRACE_SANITIZE (this);
1165 1166
    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 已提交
1167 1168
  }

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

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

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

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


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

B
Behdad Esfahbod 已提交
1223 1224
struct MarkMarkPosFormat1
{
1225 1226 1227
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1228 1229
    (this+mark1Coverage).add_coverage (c->input);
    (this+mark2Coverage).add_coverage (c->input);
1230 1231 1232
    /* TODO only add combinations that have nonzero adjustment. */
  }

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

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

    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1245
    unsigned int property;
B
Behdad Esfahbod 已提交
1246
    hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1247
    if (!skippy_iter.prev (&property)) return TRACE_RETURN (false);
1248

1249
    if (!(property & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1250

B
Behdad Esfahbod 已提交
1251 1252
    unsigned int j = skippy_iter.idx;

1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
    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 已提交
1272

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

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

B
Behdad Esfahbod 已提交
1280
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1281
    TRACE_SANITIZE (this);
1282 1283 1284
    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 已提交
1285 1286
  }

1287
  protected:
B
Behdad Esfahbod 已提交
1288
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1289 1290
  OffsetTo<Coverage>
		mark1Coverage;		/* Offset to Combining Mark1 Coverage
B
Behdad Esfahbod 已提交
1291 1292
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1293 1294
  OffsetTo<Coverage>
		mark2Coverage;		/* Offset to Combining Mark2 Coverage
B
Behdad Esfahbod 已提交
1295 1296
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1297 1298 1299 1300 1301 1302 1303
  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 */
1304 1305
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1306 1307
};

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

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

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


B
Minor  
Behdad Esfahbod 已提交
1337
struct ContextPos : Context {};
B
Behdad Esfahbod 已提交
1338

B
Minor  
Behdad Esfahbod 已提交
1339
struct ChainContextPos : ChainContext {};
B
Behdad Esfahbod 已提交
1340

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


1347

B
Behdad Esfahbod 已提交
1348 1349 1350 1351 1352
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
1353 1354
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
1355 1356
  friend struct PosLookup;

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

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

B
Behdad Esfahbod 已提交
1387
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
B
Behdad Esfahbod 已提交
1388
    TRACE_SANITIZE (this);
1389
    if (!u.header.sub_format.sanitize (c))
1390
      return TRACE_RETURN (false);
1391
    switch (lookup_type) {
1392 1393 1394 1395 1396 1397
    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));
1398
    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1399 1400 1401
    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 已提交
1402 1403 1404
    }
  }

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


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

1430 1431 1432
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
  {
B
Behdad Esfahbod 已提交
1433
    TRACE_PROCESS (this);
1434 1435 1436 1437 1438
    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).process (c, lookup_type);
      if (c->stop_sublookup_iteration (r))
B
Behdad Esfahbod 已提交
1439
        return TRACE_RETURN (r);
1440
    }
B
Behdad Esfahbod 已提交
1441
    return TRACE_RETURN (c->default_return_value ());
1442
  }
1443 1444
  template <typename context_t>
  static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index);
1445

1446 1447 1448
  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
1449
    c->set_recurse_func (NULL);
1450 1451 1452
    return TRACE_RETURN (process (c));
  }

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

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

1476 1477
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);

B
Behdad Esfahbod 已提交
1478
  inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
B
Behdad Esfahbod 已提交
1479
  {
B
Behdad Esfahbod 已提交
1480 1481
    bool ret = false;

B
Minor  
Behdad Esfahbod 已提交
1482
    if (unlikely (!c->buffer->len || !c->lookup_mask))
B
Behdad Esfahbod 已提交
1483 1484
      return false;

1485
    c->set_recurse_func (apply_recurse_func);
B
Behdad Esfahbod 已提交
1486
    c->set_lookup (*this);
1487

B
Behdad Esfahbod 已提交
1488
    c->buffer->idx = 0;
1489

1490 1491 1492
    while (c->buffer->idx < c->buffer->len)
    {
      if ((c->buffer->cur().mask & c->lookup_mask) &&
B
Behdad Esfahbod 已提交
1493
	  digest->may_have (c->buffer->cur().codepoint) &&
1494 1495 1496 1497 1498
	  apply_once (c))
	ret = true;
      else
	c->buffer->idx++;
    }
B
Behdad Esfahbod 已提交
1499 1500 1501

    return ret;
  }
B
Behdad Esfahbod 已提交
1502

B
Behdad Esfahbod 已提交
1503
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1504
    TRACE_SANITIZE (this);
1505
    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1506
    OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1507
    return TRACE_RETURN (list.sanitize (c, this, get_type ()));
B
Behdad Esfahbod 已提交
1508
  }
B
Behdad Esfahbod 已提交
1509 1510
};

B
Behdad Esfahbod 已提交
1511
typedef OffsetListOf<PosLookup> PosLookupList;
B
Behdad Esfahbod 已提交
1512 1513

/*
B
Behdad Esfahbod 已提交
1514
 * GPOS -- The Glyph Positioning Table
B
Behdad Esfahbod 已提交
1515 1516
 */

B
Behdad Esfahbod 已提交
1517 1518
struct GPOS : GSUBGPOS
{
B
Behdad Esfahbod 已提交
1519
  static const hb_tag_t Tag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1520

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

1524
  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1525
  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer, hb_bool_t zero_width_attahced_marks);
B
Behdad Esfahbod 已提交
1526

B
Behdad Esfahbod 已提交
1527
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1528
    TRACE_SANITIZE (this);
1529
    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1530
    OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1531
    return TRACE_RETURN (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1532
  }
1533 1534
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
1535 1536
};

B
Behdad Esfahbod 已提交
1537 1538 1539 1540

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

B
Behdad Esfahbod 已提交
1545
  j += i;
B
Behdad Esfahbod 已提交
1546

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

B
Behdad Esfahbod 已提交
1549
  fix_cursive_minor_offset (pos, j, direction);
B
Behdad Esfahbod 已提交
1550

B
Behdad Esfahbod 已提交
1551 1552 1553 1554
  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 已提交
1555 1556 1557
}

static void
1558
fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, hb_bool_t zero_width_attached_marks)
B
Behdad Esfahbod 已提交
1559 1560 1561 1562 1563 1564
{
  if (likely (!(pos[i].attach_lookback())))
    return;

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

1565 1566 1567 1568
  if (zero_width_attached_marks) {
    pos[i].x_advance = 0;
    pos[i].y_advance = 0;
  }
B
Behdad Esfahbod 已提交
1569 1570 1571 1572
  pos[i].x_offset += pos[j].x_offset;
  pos[i].y_offset += pos[j].y_offset;

  if (HB_DIRECTION_IS_FORWARD (direction))
1573
    for (unsigned int k = j; k < i; k++) {
B
Behdad Esfahbod 已提交
1574 1575 1576 1577
      pos[i].x_offset -= pos[k].x_advance;
      pos[i].y_offset -= pos[k].y_advance;
    }
  else
1578
    for (unsigned int k = j + 1; k < i + 1; k++) {
B
Behdad Esfahbod 已提交
1579 1580 1581 1582 1583
      pos[i].x_offset += pos[k].x_advance;
      pos[i].y_offset += pos[k].y_advance;
    }
}

B
Behdad Esfahbod 已提交
1584
void
1585
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1586 1587
{
  buffer->clear_positions ();
1588 1589 1590 1591

  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 已提交
1592 1593
}

B
Behdad Esfahbod 已提交
1594
void
1595
GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer, hb_bool_t zero_width_attached_marks)
B
Behdad Esfahbod 已提交
1596
{
1597 1598
  unsigned int len;
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
B
Behdad Esfahbod 已提交
1599 1600
  hb_direction_t direction = buffer->props.direction;

B
Behdad Esfahbod 已提交
1601 1602 1603
  /* Handle cursive connections */
  for (unsigned int i = 0; i < len; i++)
    fix_cursive_minor_offset (pos, i, direction);
B
Behdad Esfahbod 已提交
1604 1605

  /* Handle attachments */
B
Behdad Esfahbod 已提交
1606
  for (unsigned int i = 0; i < len; i++)
1607
    fix_mark_attachment (pos, i, direction, zero_width_attached_marks);
1608

1609
  HB_BUFFER_DEALLOCATE_VAR (buffer, syllable);
1610
  HB_BUFFER_DEALLOCATE_VAR (buffer, lig_props);
B
Minor  
Behdad Esfahbod 已提交
1611
  HB_BUFFER_DEALLOCATE_VAR (buffer, glyph_props);
B
Behdad Esfahbod 已提交
1612 1613
}

B
Behdad Esfahbod 已提交
1614 1615 1616

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

1617 1618 1619 1620 1621 1622 1623 1624
template <typename context_t>
inline typename context_t::return_t PosLookup::process_recurse_func (context_t *c, unsigned int lookup_index)
{
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
  const PosLookup &l = gpos.get_lookup (lookup_index);
  return l.process (c);
}

1625
inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1626
{
1627
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
B
Behdad Esfahbod 已提交
1628
  const PosLookup &l = gpos.get_lookup (lookup_index);
1629 1630
  unsigned int saved_lookup_props = c->lookup_props;
  unsigned int saved_property = c->property;
1631
  c->set_lookup (l);
1632 1633 1634 1635
  bool ret = l.apply_once (c);
  c->lookup_props = saved_lookup_props;
  c->property = saved_property;
  return ret;
B
Behdad Esfahbod 已提交
1636 1637 1638
}


B
Behdad Esfahbod 已提交
1639 1640 1641 1642
#undef attach_lookback
#undef cursive_chain


B
Behdad Esfahbod 已提交
1643
} /* namespace OT */
1644

B
Behdad Esfahbod 已提交
1645

1646
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */