hb-ot-layout-gpos-table.hh 52.4 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 60 61
    xPlacement	= 0x0001u,	/* Includes horizontal adjustment for placement */
    yPlacement	= 0x0002u,	/* Includes vertical adjustment for placement */
    xAdvance	= 0x0004u,	/* Includes horizontal adjustment for advance */
    yAdvance	= 0x0008u,	/* Includes vertical adjustment for advance */
    xPlaDevice	= 0x0010u,	/* Includes horizontal Device table for placement */
    yPlaDevice	= 0x0020u,	/* Includes vertical Device table for placement */
    xAdvDevice	= 0x0040u,	/* Includes horizontal Device table for advance */
    yAdvDevice	= 0x0080u,	/* Includes vertical Device table for advance */
    ignored	= 0x0F00u,	/* Was used in TrueType Open for MM fonts */
    reserved	= 0xF000u,	/* For future use */
62

63
    devices	= 0x00F0u	/* 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
    if (format & xAdvance) {
K
Konstantin Ritt 已提交
112 113
      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
      values++;
114
    }
115
    /* y_advance values grow downward but font-space grows upward, hence negation */
116
    if (format & yAdvance) {
K
Konstantin Ritt 已提交
117 118
      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
      values++;
119
    }
120

B
Behdad Esfahbod 已提交
121 122
    if (!has_device ()) return;

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

    if (!x_ppem && !y_ppem) return;

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

  private:
B
Behdad Esfahbod 已提交
149 150
  inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
  {
B
WIP  
Behdad Esfahbod 已提交
151 152 153 154 155 156 157
    unsigned int format = *this;

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

B
Behdad Esfahbod 已提交
158 159 160 161
    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 已提交
162 163 164 165

    return true;
  }

B
Behdad Esfahbod 已提交
166 167 168 169 170 171 172 173
  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 已提交
174 175
  public:

B
Behdad Esfahbod 已提交
176
  inline bool has_device (void) const {
B
WIP  
Behdad Esfahbod 已提交
177 178 179 180
    unsigned int format = *this;
    return (format & devices) != 0;
  }

B
Behdad Esfahbod 已提交
181 182
  inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
  {
B
Behdad Esfahbod 已提交
183
    TRACE_SANITIZE (this);
184
    return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
B
WIP  
Behdad Esfahbod 已提交
185 186
  }

B
Behdad Esfahbod 已提交
187 188
  inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
  {
B
Behdad Esfahbod 已提交
189
    TRACE_SANITIZE (this);
B
WIP  
Behdad Esfahbod 已提交
190 191
    unsigned int len = get_len ();

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

194
    if (!has_device ()) return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
195 196

    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
197
      if (!sanitize_value_devices (c, base, values))
198
        return TRACE_RETURN (false);
B
WIP  
Behdad Esfahbod 已提交
199 200 201
      values += len;
    }

202
    return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
203 204
  }

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

210
    if (!has_device ()) return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
211 212

    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
213
      if (!sanitize_value_devices (c, base, values))
214
        return TRACE_RETURN (false);
B
WIP  
Behdad Esfahbod 已提交
215 216 217
      values += stride;
    }

218
    return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
219
  }
B
Behdad Esfahbod 已提交
220 221 222
};


B
Behdad Esfahbod 已提交
223 224
struct AnchorFormat1
{
225
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
B
Behdad Esfahbod 已提交
226 227
			  hb_position_t *x, hb_position_t *y) const
  {
B
Minor  
Behdad Esfahbod 已提交
228 229
      *x = font->em_scale_x (xCoordinate);
      *y = font->em_scale_y (yCoordinate);
B
Behdad Esfahbod 已提交
230 231
  }

B
Behdad Esfahbod 已提交
232 233
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
234
    TRACE_SANITIZE (this);
235
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
236 237
  }

238
  protected:
B
Behdad Esfahbod 已提交
239 240 241
  USHORT	format;			/* Format identifier--format = 1 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
242 243
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
244 245
};

B
Behdad Esfahbod 已提交
246 247
struct AnchorFormat2
{
248
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
249 250
			  hb_position_t *x, hb_position_t *y) const
  {
251 252
      unsigned int x_ppem = font->x_ppem;
      unsigned int y_ppem = font->y_ppem;
B
Behdad Esfahbod 已提交
253
      hb_position_t cx, cy;
K
Konstantin Ritt 已提交
254
      hb_bool_t ret;
B
Behdad Esfahbod 已提交
255

K
Konstantin Ritt 已提交
256 257 258 259
      ret = (x_ppem || y_ppem) &&
             font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
      *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
      *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
B
Behdad Esfahbod 已提交
260 261
  }

B
Behdad Esfahbod 已提交
262 263
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
264
    TRACE_SANITIZE (this);
265
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
266 267
  }

268
  protected:
B
Behdad Esfahbod 已提交
269 270 271 272
  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 */
273 274
  public:
  DEFINE_SIZE_STATIC (8);
B
Behdad Esfahbod 已提交
275 276
};

B
Behdad Esfahbod 已提交
277 278
struct AnchorFormat3
{
279
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
B
Behdad Esfahbod 已提交
280 281
			  hb_position_t *x, hb_position_t *y) const
  {
B
Minor  
Behdad Esfahbod 已提交
282 283
      *x = font->em_scale_x (xCoordinate);
      *y = font->em_scale_y (yCoordinate);
284

285 286 287 288
      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 已提交
289 290
  }

B
Behdad Esfahbod 已提交
291 292
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
293
    TRACE_SANITIZE (this);
294
    return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
B
Behdad Esfahbod 已提交
295 296
  }

297
  protected:
B
Behdad Esfahbod 已提交
298 299 300 301 302 303 304 305 306 307 308
  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) */
309 310
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
311 312
};

B
Behdad Esfahbod 已提交
313 314
struct Anchor
{
315
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
316 317
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
318 319
    *x = *y = 0;
    switch (u.format) {
320 321 322 323
    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 已提交
324 325 326
    }
  }

B
Behdad Esfahbod 已提交
327 328
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
329
    TRACE_SANITIZE (this);
330
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
331
    switch (u.format) {
332 333 334 335
    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 已提交
336 337 338
    }
  }

339
  protected:
B
Behdad Esfahbod 已提交
340 341
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
342 343 344
  AnchorFormat1		format1;
  AnchorFormat2		format2;
  AnchorFormat3		format3;
B
Behdad Esfahbod 已提交
345
  } u;
B
Behdad Esfahbod 已提交
346
  public:
B
Behdad Esfahbod 已提交
347
  DEFINE_SIZE_UNION (2, format);
B
Behdad Esfahbod 已提交
348 349 350
};


351 352
struct AnchorMatrix
{
353 354
  inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
    *found = false;
355
    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
356 357
    *found = !matrixZ[row * cols + col].is_null ();
    return this+matrixZ[row * cols + col];
358 359
  }

B
Behdad Esfahbod 已提交
360 361
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
  {
B
Behdad Esfahbod 已提交
362
    TRACE_SANITIZE (this);
363 364
    if (!c->check_struct (this)) return TRACE_RETURN (false);
    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
365
    unsigned int count = rows * cols;
366
    if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return TRACE_RETURN (false);
367
    for (unsigned int i = 0; i < count; i++)
368
      if (!matrixZ[i].sanitize (c, this)) return TRACE_RETURN (false);
369
    return TRACE_RETURN (true);
370 371 372
  }

  USHORT	rows;			/* Number of rows */
373
  protected:
374
  OffsetTo<Anchor>
375
		matrixZ[VAR];		/* Matrix of offsets to Anchor tables--
376
					 * from beginning of AnchorMatrix table */
B
Behdad Esfahbod 已提交
377
  public:
378
  DEFINE_SIZE_ARRAY (2, matrixZ);
379 380 381
};


B
Behdad Esfahbod 已提交
382 383
struct MarkRecord
{
384
  friend struct MarkArray;
B
Behdad Esfahbod 已提交
385

B
Behdad Esfahbod 已提交
386 387
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
B
Behdad Esfahbod 已提交
388
    TRACE_SANITIZE (this);
389
    return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
390 391
  }

392
  protected:
B
Behdad Esfahbod 已提交
393 394 395 396
  USHORT	klass;			/* Class defined for this mark */
  OffsetTo<Anchor>
		markAnchor;		/* Offset to Anchor table--from
					 * beginning of MarkArray table */
B
Behdad Esfahbod 已提交
397 398
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
399 400
};

B
Behdad Esfahbod 已提交
401
struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
B
Behdad Esfahbod 已提交
402
{
B
Behdad Esfahbod 已提交
403
  inline bool apply (hb_apply_context_t *c,
404 405 406 407
		     unsigned int mark_index, unsigned int glyph_index,
		     const AnchorMatrix &anchors, unsigned int class_count,
		     unsigned int glyph_pos) const
  {
B
Behdad Esfahbod 已提交
408
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
409
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
410
    const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
411 412 413
    unsigned int mark_class = record.klass;

    const Anchor& mark_anchor = this + record.markAnchor;
414 415 416 417 418
    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);
419 420 421

    hb_position_t mark_x, mark_y, base_x, base_y;

B
Behdad Esfahbod 已提交
422 423
    mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
    glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
424

B
Behdad Esfahbod 已提交
425
    hb_glyph_position_t &o = buffer->cur_pos();
B
Behdad Esfahbod 已提交
426 427
    o.x_offset = base_x - mark_x;
    o.y_offset = base_y - mark_y;
B
Behdad Esfahbod 已提交
428
    o.attach_lookback() = buffer->idx - glyph_pos;
429

B
Behdad Esfahbod 已提交
430
    buffer->idx++;
431
    return TRACE_RETURN (true);
432
  }
B
Behdad Esfahbod 已提交
433

B
Behdad Esfahbod 已提交
434 435
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
436
    TRACE_SANITIZE (this);
437
    return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
B
Behdad Esfahbod 已提交
438
  }
B
Behdad Esfahbod 已提交
439 440 441 442 443
};


/* Lookups */

B
Behdad Esfahbod 已提交
444 445
struct SinglePosFormat1
{
446 447 448
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
449
    (this+coverage).add_coverage (c->input);
450 451
  }

452 453 454 455 456
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
457
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
458
  {
B
Behdad Esfahbod 已提交
459
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
460 461
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
462
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
463

464
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
465
			     values, buffer->cur_pos());
466

B
Behdad Esfahbod 已提交
467
    buffer->idx++;
468
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
469 470
  }

B
Behdad Esfahbod 已提交
471 472
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
473
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
474 475 476
    return TRACE_RETURN (c->check_struct (this)
        && coverage.sanitize (c, this)
	&& valueFormat.sanitize_value (c, this, values));
B
Behdad Esfahbod 已提交
477 478
  }

479
  protected:
B
Behdad Esfahbod 已提交
480 481 482 483
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
484
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
485 486 487 488
					 * ValueRecord */
  ValueRecord	values;			/* Defines positioning
					 * value(s)--applied to all glyphs in
					 * the Coverage table */
B
Behdad Esfahbod 已提交
489
  public:
490
  DEFINE_SIZE_ARRAY (6, values);
B
Behdad Esfahbod 已提交
491 492
};

B
Behdad Esfahbod 已提交
493 494
struct SinglePosFormat2
{
495 496 497
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
498
    (this+coverage).add_coverage (c->input);
499 500
  }

501 502 503 504 505
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
506
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
507
  {
B
Behdad Esfahbod 已提交
508
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
509 510
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
511
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
512

513
    if (likely (index >= valueCount)) return TRACE_RETURN (false);
514

515
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
516
			     &values[index * valueFormat.get_len ()],
B
Behdad Esfahbod 已提交
517
			     buffer->cur_pos());
518

B
Behdad Esfahbod 已提交
519
    buffer->idx++;
520
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
521 522
  }

B
Behdad Esfahbod 已提交
523 524
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
525
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
526 527 528
    return TRACE_RETURN (c->check_struct (this)
	&& coverage.sanitize (c, this)
	&& valueFormat.sanitize_values (c, this, values, valueCount));
B
Behdad Esfahbod 已提交
529 530
  }

531
  protected:
B
Behdad Esfahbod 已提交
532 533 534 535
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
536
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
537 538 539 540
					 * ValueRecord */
  USHORT	valueCount;		/* Number of ValueRecords */
  ValueRecord	values;			/* Array of ValueRecords--positioning
					 * values applied to glyphs */
B
Behdad Esfahbod 已提交
541
  public:
542
  DEFINE_SIZE_ARRAY (8, values);
B
Behdad Esfahbod 已提交
543 544
};

B
Behdad Esfahbod 已提交
545 546
struct SinglePos
{
547
  template <typename context_t>
548
  inline typename context_t::return_t dispatch (context_t *c) const
549
  {
550
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
551
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
552
    switch (u.format) {
553 554
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
B
Behdad Esfahbod 已提交
555
    default:return TRACE_RETURN (c->default_return_value ());
556 557 558
    }
  }

B
Behdad Esfahbod 已提交
559 560
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
561
    TRACE_SANITIZE (this);
562
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
563
    switch (u.format) {
564 565 566
    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 已提交
567 568 569
    }
  }

570
  protected:
B
Behdad Esfahbod 已提交
571 572
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
573 574
  SinglePosFormat1	format1;
  SinglePosFormat2	format2;
B
Behdad Esfahbod 已提交
575 576 577 578
  } u;
};


B
Behdad Esfahbod 已提交
579 580
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
581
  friend struct PairSet;
B
Behdad Esfahbod 已提交
582

583
  protected:
B
Behdad Esfahbod 已提交
584 585 586 587 588
  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 已提交
589
  public:
590
  DEFINE_SIZE_ARRAY (2, values);
B
Behdad Esfahbod 已提交
591 592
};

B
Behdad Esfahbod 已提交
593 594
struct PairSet
{
B
Behdad Esfahbod 已提交
595 596
  friend struct PairPosFormat1;

597 598 599 600 601 602 603 604
  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);

605
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
606 607 608
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
    {
B
Minor  
Behdad Esfahbod 已提交
609
      c->input->add (record->secondGlyph);
610 611 612 613
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }
  }

B
Behdad Esfahbod 已提交
614
  inline bool apply (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
615 616 617
		     const ValueFormat *valueFormats,
		     unsigned int pos) const
  {
B
Behdad Esfahbod 已提交
618
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
619
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
620 621 622 623
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);

624
    const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
625
    unsigned int count = len;
626 627 628 629 630 631 632

    /* Hand-coded bsearch. */
    if (unlikely (!count))
      return TRACE_RETURN (false);
    hb_codepoint_t x = buffer->info[pos].codepoint;
    int min = 0, max = (int) count - 1;
    while (min <= max)
B
Behdad Esfahbod 已提交
633
    {
634 635 636 637 638 639 640 641
      int mid = (min + max) / 2;
      const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
      hb_codepoint_t mid_x = record->secondGlyph;
      if (x < mid_x)
        max = mid - 1;
      else if (x > mid_x)
        min = mid + 1;
      else
B
Behdad Esfahbod 已提交
642
      {
643
	valueFormats[0].apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
644
				     &record->values[0], buffer->cur_pos());
645
	valueFormats[1].apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
646
				     &record->values[len1], buffer->pos[pos]);
B
Behdad Esfahbod 已提交
647 648
	if (len2)
	  pos++;
B
Behdad Esfahbod 已提交
649
	buffer->idx = pos;
650
	return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
651 652 653
      }
    }

654
    return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
655 656 657
  }

  struct sanitize_closure_t {
B
Behdad Esfahbod 已提交
658 659
    const void *base;
    const ValueFormat *valueFormats;
B
Behdad Esfahbod 已提交
660 661 662 663
    unsigned int len1; /* valueFormats[0].get_len() */
    unsigned int stride; /* 1 + len1 + len2 */
  };

B
Behdad Esfahbod 已提交
664 665
  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
  {
B
Behdad Esfahbod 已提交
666
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
667
    if (!(c->check_struct (this)
668
       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
669 670

    unsigned int count = len;
B
Behdad Esfahbod 已提交
671
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
672 673
    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 已提交
674 675
  }

676
  protected:
B
Behdad Esfahbod 已提交
677
  USHORT	len;			/* Number of PairValueRecords */
678
  USHORT	arrayZ[VAR];		/* Array of PairValueRecords--ordered
B
Behdad Esfahbod 已提交
679
					 * by GlyphID of the second glyph */
B
Behdad Esfahbod 已提交
680
  public:
681
  DEFINE_SIZE_ARRAY (2, arrayZ);
B
Behdad Esfahbod 已提交
682
};
B
Behdad Esfahbod 已提交
683

B
Behdad Esfahbod 已提交
684 685
struct PairPosFormat1
{
686 687 688
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
689
    (this+coverage).add_coverage (c->input);
690 691 692 693 694
    unsigned int count = pairSet.len;
    for (unsigned int i = 0; i < count; i++)
      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
  }

695 696 697 698 699
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
700
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
701
  {
B
Behdad Esfahbod 已提交
702
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
703 704
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
705
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
706

707
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
708
    skippy_iter.reset (buffer->idx, 1);
709
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
710

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

B
Behdad Esfahbod 已提交
714 715
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
716
    TRACE_SANITIZE (this);
717 718 719

    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
B
Behdad Esfahbod 已提交
720 721 722 723 724 725
    PairSet::sanitize_closure_t closure = {
      this,
      &valueFormat1,
      len1,
      1 + len1 + len2
    };
726

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

730
  protected:
B
Behdad Esfahbod 已提交
731 732 733 734
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
735
  ValueFormat	valueFormat1;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
736 737
					 * ValueRecord1--for the first glyph
					 * in the pair--may be zero (0) */
738
  ValueFormat	valueFormat2;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
739 740 741 742 743
					 * ValueRecord2--for the second glyph
					 * in the pair--may be zero (0) */
  OffsetArrayOf<PairSet>
		pairSet;		/* Array of PairSet tables
					 * ordered by Coverage Index */
744
  public:
745
  DEFINE_SIZE_ARRAY (10, pairSet);
B
Behdad Esfahbod 已提交
746 747
};

B
Behdad Esfahbod 已提交
748 749
struct PairPosFormat2
{
750 751 752
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
753
    /* (this+coverage).add_coverage (c->input); // Don't need this. */
754 755 756 757

    unsigned int count1 = class1Count;
    const ClassDef &klass1 = this+classDef1;
    for (unsigned int i = 0; i < count1; i++)
B
Minor  
Behdad Esfahbod 已提交
758
      klass1.add_class (c->input, i);
759 760 761 762

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

766 767 768 769 770
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
771
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
772
  {
B
Behdad Esfahbod 已提交
773
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
774 775
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
776
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
777

778
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
779
    skippy_iter.reset (buffer->idx, 1);
780
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
781 782 783 784 785

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

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

B
Behdad Esfahbod 已提交
790
    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
791
    valueFormat1.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
792
			      v, buffer->cur_pos());
793
    valueFormat2.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
794
			      v + len1, buffer->pos[skippy_iter.idx]);
B
Behdad Esfahbod 已提交
795

B
Behdad Esfahbod 已提交
796
    buffer->idx = skippy_iter.idx;
B
Behdad Esfahbod 已提交
797
    if (len2)
B
Behdad Esfahbod 已提交
798
      buffer->idx++;
B
Behdad Esfahbod 已提交
799

800
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
801 802
  }

B
Behdad Esfahbod 已提交
803 804
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
805
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
806 807 808
    if (!(c->check_struct (this)
       && coverage.sanitize (c, this)
       && classDef1.sanitize (c, this)
809
       && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
810

811 812 813
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int stride = len1 + len2;
B
Behdad Esfahbod 已提交
814
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
815
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
816 817 818
    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 已提交
819
  }
B
Behdad Esfahbod 已提交
820

821
  protected:
B
Behdad Esfahbod 已提交
822 823 824 825
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
826
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
827 828
					 * first glyph of the pair--may be zero
					 * (0) */
829
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
					 * 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 已提交
847
  public:
848
  DEFINE_SIZE_ARRAY (16, values);
B
Behdad Esfahbod 已提交
849 850
};

B
Behdad Esfahbod 已提交
851 852
struct PairPos
{
853
  template <typename context_t>
854
  inline typename context_t::return_t dispatch (context_t *c) const
855
  {
856
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
857
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
858
    switch (u.format) {
859 860
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
B
Behdad Esfahbod 已提交
861
    default:return TRACE_RETURN (c->default_return_value ());
862 863 864
    }
  }

B
Behdad Esfahbod 已提交
865 866
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
867
    TRACE_SANITIZE (this);
868
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
869
    switch (u.format) {
870 871 872
    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 已提交
873 874 875
    }
  }

876
  protected:
B
Behdad Esfahbod 已提交
877 878
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
879 880
  PairPosFormat1	format1;
  PairPosFormat2	format2;
B
Behdad Esfahbod 已提交
881 882 883 884
  } u;
};


B
Behdad Esfahbod 已提交
885 886
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
887 888
  friend struct CursivePosFormat1;

B
Behdad Esfahbod 已提交
889 890
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
B
Behdad Esfahbod 已提交
891
    TRACE_SANITIZE (this);
892
    return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
893 894
  }

895
  protected:
B
Behdad Esfahbod 已提交
896 897 898 899 900 901 902 903
  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 已提交
904 905
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
906 907
};

B
Behdad Esfahbod 已提交
908 909
struct CursivePosFormat1
{
910 911 912
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
913
    (this+coverage).add_coverage (c->input);
914 915
  }

916 917 918 919 920
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
921
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
922
  {
B
Behdad Esfahbod 已提交
923
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
924
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
925 926

    /* We don't handle mark glyphs here. */
B
Behdad Esfahbod 已提交
927
    if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
928

B
Behdad Esfahbod 已提交
929
    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
930
    if (!this_record.exitAnchor) return TRACE_RETURN (false);
931

932
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
933
    skippy_iter.reset (buffer->idx, 1);
934
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
935

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

B
Behdad Esfahbod 已提交
939
    unsigned int i = buffer->idx;
B
Behdad Esfahbod 已提交
940
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
941

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

B
Behdad Esfahbod 已提交
946
    hb_glyph_position_t *pos = buffer->pos;
B
Behdad Esfahbod 已提交
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981

    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 已提交
982 983
    }

B
Behdad Esfahbod 已提交
984 985 986
    /* Cross-direction adjustment */
    if  (c->lookup_props & LookupFlag::RightToLeft) {
      pos[i].cursive_chain() = j - i;
987
      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
B
Behdad Esfahbod 已提交
988
	pos[i].y_offset = entry_y - exit_y;
989
      else
B
Behdad Esfahbod 已提交
990 991 992
	pos[i].x_offset = entry_x - exit_x;
    } else {
      pos[j].cursive_chain() = i - j;
993
      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
B
Behdad Esfahbod 已提交
994
	pos[j].y_offset = exit_y - entry_y;
995
      else
B
Behdad Esfahbod 已提交
996
	pos[j].x_offset = exit_x - entry_x;
B
Behdad Esfahbod 已提交
997 998
    }

B
Behdad Esfahbod 已提交
999
    buffer->idx = j;
1000
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1001 1002
  }

B
Behdad Esfahbod 已提交
1003 1004
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1005
    TRACE_SANITIZE (this);
1006
    return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
B
Behdad Esfahbod 已提交
1007 1008
  }

1009
  protected:
B
Behdad Esfahbod 已提交
1010 1011 1012 1013 1014 1015 1016
  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 */
1017
  public:
1018
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
B
Behdad Esfahbod 已提交
1019 1020
};

B
Behdad Esfahbod 已提交
1021 1022
struct CursivePos
{
1023
  template <typename context_t>
1024
  inline typename context_t::return_t dispatch (context_t *c) const
1025
  {
1026
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
1027
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1028
    switch (u.format) {
1029
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1030
    default:return TRACE_RETURN (c->default_return_value ());
1031 1032 1033
    }
  }

B
Behdad Esfahbod 已提交
1034 1035
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1036
    TRACE_SANITIZE (this);
1037
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1038
    switch (u.format) {
1039 1040
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1041 1042 1043
    }
  }

1044
  protected:
B
Behdad Esfahbod 已提交
1045 1046
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1047
  CursivePosFormat1	format1;
B
Behdad Esfahbod 已提交
1048 1049 1050 1051
  } u;
};


1052 1053 1054
typedef AnchorMatrix BaseArray;		/* base-major--
					 * in order of BaseCoverage Index--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1055
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1056

B
Behdad Esfahbod 已提交
1057 1058
struct MarkBasePosFormat1
{
1059 1060 1061
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1062 1063
    (this+markCoverage).add_coverage (c->input);
    (this+baseCoverage).add_coverage (c->input);
1064 1065
  }

1066 1067 1068 1069 1070
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1071
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1072
  {
B
Behdad Esfahbod 已提交
1073
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1074 1075
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1076
    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1077 1078

    /* now we search backwards for a non-mark glyph */
1079
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1080
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
1081
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1082
    do {
B
Behdad Esfahbod 已提交
1083
      if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1084
      /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
B
Behdad Esfahbod 已提交
1085
      if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
1086 1087
      skippy_iter.reject ();
    } while (1);
1088

B
Behdad Esfahbod 已提交
1089
    /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
B
Behdad Esfahbod 已提交
1090
    if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
B
Behdad Esfahbod 已提交
1091

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

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

B
Behdad Esfahbod 已提交
1098 1099
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1100
    TRACE_SANITIZE (this);
1101 1102
    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 已提交
1103 1104
  }

1105
  protected:
B
Behdad Esfahbod 已提交
1106
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1107 1108
  OffsetTo<Coverage>
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
1109
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1110 1111
  OffsetTo<Coverage>
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
1112 1113
					 * beginning of MarkBasePos subtable */
  USHORT	classCount;		/* Number of classes defined for marks */
B
Behdad Esfahbod 已提交
1114 1115
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1116
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1117 1118
  OffsetTo<BaseArray>
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
1119
					 * beginning of MarkBasePos subtable */
1120 1121
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1122 1123
};

B
Behdad Esfahbod 已提交
1124 1125
struct MarkBasePos
{
1126
  template <typename context_t>
1127
  inline typename context_t::return_t dispatch (context_t *c) const
1128
  {
1129
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
1130
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1131
    switch (u.format) {
1132
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1133
    default:return TRACE_RETURN (c->default_return_value ());
1134 1135 1136
    }
  }

B
Behdad Esfahbod 已提交
1137 1138
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1139
    TRACE_SANITIZE (this);
1140
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1141
    switch (u.format) {
1142 1143
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1144 1145 1146
    }
  }

1147
  protected:
B
Behdad Esfahbod 已提交
1148 1149
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1150
  MarkBasePosFormat1	format1;
B
Behdad Esfahbod 已提交
1151 1152 1153 1154
  } u;
};


1155 1156 1157
typedef AnchorMatrix LigatureAttach;	/* component-major--
					 * in order of writing direction--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1158
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1159

1160
typedef OffsetListOf<LigatureAttach> LigatureArray;
B
Behdad Esfahbod 已提交
1161
					/* Array of LigatureAttach
B
Behdad Esfahbod 已提交
1162 1163 1164
					 * tables ordered by
					 * LigatureCoverage Index */

B
Behdad Esfahbod 已提交
1165 1166
struct MarkLigPosFormat1
{
1167 1168 1169
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1170 1171
    (this+markCoverage).add_coverage (c->input);
    (this+ligatureCoverage).add_coverage (c->input);
1172 1173
  }

1174 1175 1176 1177 1178
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1179
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1180
  {
B
Behdad Esfahbod 已提交
1181
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1182 1183
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1184
    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1185 1186

    /* now we search backwards for a non-mark glyph */
1187
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1188
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
1189 1190
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1191

B
Behdad Esfahbod 已提交
1192
    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
B
Behdad Esfahbod 已提交
1193
    if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
B
Behdad Esfahbod 已提交
1194

B
Behdad Esfahbod 已提交
1195
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
1196
    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
1197
    if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1198 1199

    const LigatureArray& lig_array = this+ligatureArray;
1200
    const LigatureAttach& lig_attach = lig_array[lig_index];
1201 1202

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

B
Behdad Esfahbod 已提交
1206 1207 1208 1209
    /* 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 已提交
1210
    unsigned int comp_index;
B
Behdad Esfahbod 已提交
1211 1212 1213
    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
B
Behdad Esfahbod 已提交
1214
    if (lig_id && lig_id == mark_id && mark_comp > 0)
B
Behdad Esfahbod 已提交
1215
      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
B
Behdad Esfahbod 已提交
1216
    else
B
Behdad Esfahbod 已提交
1217
      comp_index = comp_count - 1;
B
Behdad Esfahbod 已提交
1218

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

B
Behdad Esfahbod 已提交
1222 1223
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1224
    TRACE_SANITIZE (this);
1225 1226
    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 已提交
1227 1228
  }

1229
  protected:
B
Behdad Esfahbod 已提交
1230
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1231 1232
  OffsetTo<Coverage>
		markCoverage;		/* Offset to Mark Coverage table--from
B
Behdad Esfahbod 已提交
1233
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1234 1235
  OffsetTo<Coverage>
		ligatureCoverage;	/* Offset to Ligature Coverage
B
Behdad Esfahbod 已提交
1236 1237 1238
					 * table--from beginning of MarkLigPos
					 * subtable */
  USHORT	classCount;		/* Number of defined mark classes */
B
Behdad Esfahbod 已提交
1239 1240
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1241
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1242 1243
  OffsetTo<LigatureArray>
		ligatureArray;		/* Offset to LigatureArray table--from
B
Behdad Esfahbod 已提交
1244
					 * beginning of MarkLigPos subtable */
1245 1246
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1247 1248
};

B
Behdad Esfahbod 已提交
1249 1250
struct MarkLigPos
{
1251
  template <typename context_t>
1252
  inline typename context_t::return_t dispatch (context_t *c) const
1253
  {
1254
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
1255
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1256
    switch (u.format) {
1257
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1258
    default:return TRACE_RETURN (c->default_return_value ());
1259 1260 1261
    }
  }

B
Behdad Esfahbod 已提交
1262 1263
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1264
    TRACE_SANITIZE (this);
1265
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1266
    switch (u.format) {
1267 1268
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1269 1270 1271
    }
  }

1272
  protected:
B
Behdad Esfahbod 已提交
1273 1274
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1275
  MarkLigPosFormat1	format1;
B
Behdad Esfahbod 已提交
1276 1277 1278 1279
  } u;
};


1280 1281 1282 1283
typedef AnchorMatrix Mark2Array;	/* mark2-major--
					 * in order of Mark2Coverage Index--,
					 * mark1-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1284

B
Behdad Esfahbod 已提交
1285 1286
struct MarkMarkPosFormat1
{
1287 1288 1289
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1290 1291
    (this+mark1Coverage).add_coverage (c->input);
    (this+mark2Coverage).add_coverage (c->input);
1292 1293
  }

1294 1295 1296 1297 1298
  inline const Coverage &get_coverage (void) const
  {
    return this+mark1Coverage;
  }

B
Behdad Esfahbod 已提交
1299
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1300
  {
B
Behdad Esfahbod 已提交
1301
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1302 1303
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
1304
    if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1305 1306

    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1307
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1308
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
1309 1310
    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1311

B
Behdad Esfahbod 已提交
1312
    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
B
Behdad Esfahbod 已提交
1313

B
Behdad Esfahbod 已提交
1314 1315
    unsigned int j = skippy_iter.idx;

B
Behdad Esfahbod 已提交
1316 1317 1318 1319
    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334

    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 已提交
1335

1336
    good:
B
Behdad Esfahbod 已提交
1337
    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
1338
    if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1339

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

B
Behdad Esfahbod 已提交
1343 1344
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1345
    TRACE_SANITIZE (this);
1346 1347 1348
    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 已提交
1349 1350
  }

1351
  protected:
B
Behdad Esfahbod 已提交
1352
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1353 1354
  OffsetTo<Coverage>
		mark1Coverage;		/* Offset to Combining Mark1 Coverage
B
Behdad Esfahbod 已提交
1355 1356
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1357 1358
  OffsetTo<Coverage>
		mark2Coverage;		/* Offset to Combining Mark2 Coverage
B
Behdad Esfahbod 已提交
1359 1360
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1361 1362 1363 1364 1365 1366 1367
  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 */
1368 1369
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1370 1371
};

B
Behdad Esfahbod 已提交
1372 1373
struct MarkMarkPos
{
1374
  template <typename context_t>
1375
  inline typename context_t::return_t dispatch (context_t *c) const
1376
  {
1377
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
1378
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1379
    switch (u.format) {
1380
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1381
    default:return TRACE_RETURN (c->default_return_value ());
1382 1383 1384
    }
  }

B
Behdad Esfahbod 已提交
1385 1386
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1387
    TRACE_SANITIZE (this);
1388
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1389
    switch (u.format) {
1390 1391
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1392 1393 1394
    }
  }

1395
  protected:
B
Behdad Esfahbod 已提交
1396 1397
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1398
  MarkMarkPosFormat1	format1;
B
Behdad Esfahbod 已提交
1399 1400 1401 1402
  } u;
};


B
Minor  
Behdad Esfahbod 已提交
1403
struct ContextPos : Context {};
B
Behdad Esfahbod 已提交
1404

B
Minor  
Behdad Esfahbod 已提交
1405
struct ChainContextPos : ChainContext {};
B
Behdad Esfahbod 已提交
1406

B
Behdad Esfahbod 已提交
1407
struct ExtensionPos : Extension<ExtensionPos>
B
Behdad Esfahbod 已提交
1408
{
1409
  typedef struct PosLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
1410 1411 1412
};


1413

B
Behdad Esfahbod 已提交
1414 1415 1416 1417 1418
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
1419 1420
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
1421 1422
  friend struct PosLookup;

B
Behdad Esfahbod 已提交
1423
  enum Type {
1424 1425 1426 1427 1428 1429 1430 1431
    Single		= 1,
    Pair		= 2,
    Cursive		= 3,
    MarkBase		= 4,
    MarkLig		= 5,
    MarkMark		= 6,
    Context		= 7,
    ChainContext	= 8,
1432
    Extension		= 9
1433 1434
  };

1435
  template <typename context_t>
1436
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1437
  {
1438
    TRACE_DISPATCH (this, lookup_type);
B
Behdad Esfahbod 已提交
1439
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
1440
    switch (lookup_type) {
1441 1442 1443 1444 1445 1446 1447 1448 1449
    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 已提交
1450
    default:			return TRACE_RETURN (c->default_return_value ());
1451
    }
1452 1453
  }

B
Behdad Esfahbod 已提交
1454 1455
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) const
  {
B
Behdad Esfahbod 已提交
1456
    TRACE_SANITIZE (this);
1457
    switch (lookup_type) {
1458 1459 1460 1461 1462 1463
    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));
1464
    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1465 1466 1467
    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 已提交
1468 1469 1470
    }
  }

1471
  protected:
B
Behdad Esfahbod 已提交
1472
  union {
B
Minor  
Behdad Esfahbod 已提交
1473
  USHORT		sub_format;
B
Behdad Esfahbod 已提交
1474 1475 1476 1477 1478 1479
  SinglePos		single;
  PairPos		pair;
  CursivePos		cursive;
  MarkBasePos		markBase;
  MarkLigPos		markLig;
  MarkMarkPos		markMark;
1480
  ContextPos		context;
B
Behdad Esfahbod 已提交
1481 1482
  ChainContextPos	chainContext;
  ExtensionPos		extension;
B
Behdad Esfahbod 已提交
1483
  } u;
B
Behdad Esfahbod 已提交
1484
  public:
B
Minor  
Behdad Esfahbod 已提交
1485
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1486 1487 1488
};


B
Behdad Esfahbod 已提交
1489 1490
struct PosLookup : Lookup
{
1491 1492
  inline const PosLookupSubTable& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
B
Behdad Esfahbod 已提交
1493

B
Behdad Esfahbod 已提交
1494 1495 1496 1497 1498
  inline bool is_reverse (void) const
  {
    return false;
  }

B
Behdad Esfahbod 已提交
1499
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1500 1501
  {
    TRACE_COLLECT_GLYPHS (this);
1502
    c->set_recurse_func (NULL);
1503
    return TRACE_RETURN (dispatch (c));
1504 1505
  }

B
Behdad Esfahbod 已提交
1506 1507 1508
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1509
    hb_get_coverage_context_t c;
B
Behdad Esfahbod 已提交
1510 1511 1512
    const Coverage *last = NULL;
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
1513
      const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
1514 1515 1516
      if (coverage != last) {
        coverage->add_coverage (glyphs);
        last = coverage;
B
Behdad Esfahbod 已提交
1517 1518 1519 1520
      }
    }
  }

1521
  inline bool apply_once (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1522
  {
B
Behdad Esfahbod 已提交
1523
    TRACE_APPLY (this);
1524
    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
B
Behdad Esfahbod 已提交
1525
      return TRACE_RETURN (false);
1526
    return TRACE_RETURN (dispatch (c));
B
Behdad Esfahbod 已提交
1527 1528
  }

1529 1530
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);

B
Behdad Esfahbod 已提交
1531 1532 1533 1534 1535 1536 1537
  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
  {
    unsigned int lookup_type = get_type ();
1538
    TRACE_DISPATCH (this, lookup_type);
B
Behdad Esfahbod 已提交
1539 1540 1541 1542 1543 1544 1545 1546 1547
    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 已提交
1548 1549
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1550
    TRACE_SANITIZE (this);
1551
    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1552
    const OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1553
    return TRACE_RETURN (list.sanitize (c, this, get_type ()));
B
Behdad Esfahbod 已提交
1554
  }
B
Behdad Esfahbod 已提交
1555 1556
};

B
Behdad Esfahbod 已提交
1557
typedef OffsetListOf<PosLookup> PosLookupList;
B
Behdad Esfahbod 已提交
1558 1559

/*
B
Behdad Esfahbod 已提交
1560
 * GPOS -- The Glyph Positioning Table
B
Behdad Esfahbod 已提交
1561 1562
 */

B
Behdad Esfahbod 已提交
1563 1564
struct GPOS : GSUBGPOS
{
1565
  static const hb_tag_t tableTag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1566

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

1570
  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1571
  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
B
Behdad Esfahbod 已提交
1572

B
Behdad Esfahbod 已提交
1573 1574
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1575
    TRACE_SANITIZE (this);
1576
    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1577
    const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1578
    return TRACE_RETURN (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1579
  }
1580 1581
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
1582 1583
};

B
Behdad Esfahbod 已提交
1584 1585 1586 1587

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

B
Behdad Esfahbod 已提交
1592
  j += i;
B
Behdad Esfahbod 已提交
1593

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

B
Behdad Esfahbod 已提交
1596
  fix_cursive_minor_offset (pos, j, direction);
B
Behdad Esfahbod 已提交
1597

B
Behdad Esfahbod 已提交
1598 1599 1600 1601
  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 已提交
1602 1603 1604
}

static void
1605
fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
B
Behdad Esfahbod 已提交
1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
{
  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))
1616
    for (unsigned int k = j; k < i; k++) {
B
Behdad Esfahbod 已提交
1617 1618 1619 1620
      pos[i].x_offset -= pos[k].x_advance;
      pos[i].y_offset -= pos[k].y_advance;
    }
  else
1621
    for (unsigned int k = j + 1; k < i + 1; k++) {
B
Behdad Esfahbod 已提交
1622 1623 1624 1625 1626
      pos[i].x_offset += pos[k].x_advance;
      pos[i].y_offset += pos[k].y_advance;
    }
}

B
Behdad Esfahbod 已提交
1627
void
1628
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1629 1630
{
  buffer->clear_positions ();
1631 1632 1633 1634

  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 已提交
1635 1636
}

B
Behdad Esfahbod 已提交
1637
void
1638
GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1639
{
1640 1641
  _hb_buffer_assert_gsubgpos_vars (buffer);

1642 1643
  unsigned int len;
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
B
Behdad Esfahbod 已提交
1644 1645
  hb_direction_t direction = buffer->props.direction;

B
Behdad Esfahbod 已提交
1646 1647 1648
  /* Handle cursive connections */
  for (unsigned int i = 0; i < len; i++)
    fix_cursive_minor_offset (pos, i, direction);
B
Behdad Esfahbod 已提交
1649 1650

  /* Handle attachments */
B
Behdad Esfahbod 已提交
1651
  for (unsigned int i = 0; i < len; i++)
1652
    fix_mark_attachment (pos, i, direction);
B
Behdad Esfahbod 已提交
1653 1654
}

B
Behdad Esfahbod 已提交
1655 1656 1657

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

1658
template <typename context_t>
1659
/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1660 1661 1662
{
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
  const PosLookup &l = gpos.get_lookup (lookup_index);
1663
  return l.dispatch (c);
1664 1665
}

1666
/*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1667
{
1668
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
B
Behdad Esfahbod 已提交
1669
  const PosLookup &l = gpos.get_lookup (lookup_index);
1670
  unsigned int saved_lookup_props = c->lookup_props;
1671
  c->set_lookup (l);
1672
  bool ret = l.apply_once (c);
1673
  c->set_lookup_props (saved_lookup_props);
1674
  return ret;
B
Behdad Esfahbod 已提交
1675 1676 1677
}


B
Behdad Esfahbod 已提交
1678 1679 1680 1681
#undef attach_lookback
#undef cursive_chain


B
Behdad Esfahbod 已提交
1682
} /* namespace OT */
1683

B
Behdad Esfahbod 已提交
1684

1685
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */