hb-ot-layout-gpos-table.hh 50.8 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 */
39 40 41 42 43 44 45 46 47 48 49
#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
#define attach_type() var.u8[2] /* attachment type */
/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */

enum attach_type_t {
  ATTACH_TYPE_NONE	= 0X00,

  /* Each attachment should be either a mark or a cursive; can't be both. */
  ATTACH_TYPE_MARK	= 0X01,
  ATTACH_TYPE_CURSIVE	= 0X02,
};
B
Behdad Esfahbod 已提交
50 51


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

B
Behdad Esfahbod 已提交
54
typedef USHORT Value;
55

56
typedef Value ValueRecord[VAR];
B
Behdad Esfahbod 已提交
57

B
Behdad Esfahbod 已提交
58 59
struct ValueFormat : USHORT
{
B
Behdad Esfahbod 已提交
60
  enum Flags {
61 62 63 64 65 66 67 68 69 70
    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 */
71

72
    devices	= 0x00F0u	/* Mask for having any Device table */
B
WIP  
Behdad Esfahbod 已提交
73
  };
74

B
WIP  
Behdad Esfahbod 已提交
75
/* All fields are options.  Only those available advance the value pointer. */
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
#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
100

B
Behdad Esfahbod 已提交
101
  inline unsigned int get_len (void) const
B
WIP  
Behdad Esfahbod 已提交
102
  { return _hb_popcount32 ((unsigned int) *this); }
B
Behdad Esfahbod 已提交
103
  inline unsigned int get_size (void) const
B
Behdad Esfahbod 已提交
104
  { return get_len () * Value::static_size; }
B
WIP  
Behdad Esfahbod 已提交
105

106
  void apply_value (hb_font_t            *font,
107
		    hb_direction_t        direction,
108 109 110
		    const void           *base,
		    const Value          *values,
		    hb_glyph_position_t  &glyph_pos) const
B
WIP  
Behdad Esfahbod 已提交
111 112 113
  {
    unsigned int x_ppem, y_ppem;
    unsigned int format = *this;
114
    hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
B
WIP  
Behdad Esfahbod 已提交
115 116 117

    if (!format) return;

B
Minor  
Behdad Esfahbod 已提交
118 119
    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++));
120
    if (format & xAdvance) {
K
Konstantin Ritt 已提交
121 122
      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
      values++;
123
    }
124
    /* y_advance values grow downward but font-space grows upward, hence negation */
125
    if (format & yAdvance) {
K
Konstantin Ritt 已提交
126 127
      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
      values++;
128
    }
129

B
Behdad Esfahbod 已提交
130 131
    if (!has_device ()) return;

132 133
    x_ppem = font->x_ppem;
    y_ppem = font->y_ppem;
B
Behdad Esfahbod 已提交
134 135 136

    if (!x_ppem && !y_ppem) return;

137 138
    /* pixel -> fractional pixel */
    if (format & xPlaDevice) {
K
Konstantin Ritt 已提交
139 140
      if (x_ppem) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font);
      values++;
141 142
    }
    if (format & yPlaDevice) {
K
Konstantin Ritt 已提交
143 144
      if (y_ppem) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font);
      values++;
145 146
    }
    if (format & xAdvDevice) {
K
Konstantin Ritt 已提交
147 148
      if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
      values++;
149 150
    }
    if (format & yAdvDevice) {
151
      /* y_advance values grow downward but font-space grows upward, hence negation */
K
Konstantin Ritt 已提交
152 153
      if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
      values++;
154 155
    }
  }
B
WIP  
Behdad Esfahbod 已提交
156 157

  private:
B
Behdad Esfahbod 已提交
158 159
  inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
  {
B
WIP  
Behdad Esfahbod 已提交
160 161 162 163 164 165 166
    unsigned int format = *this;

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

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

    return true;
  }

B
Behdad Esfahbod 已提交
175 176 177 178 179 180 181 182
  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 已提交
183 184
  public:

B
Behdad Esfahbod 已提交
185
  inline bool has_device (void) const {
B
WIP  
Behdad Esfahbod 已提交
186 187 188 189
    unsigned int format = *this;
    return (format & devices) != 0;
  }

B
Behdad Esfahbod 已提交
190 191
  inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
  {
B
Behdad Esfahbod 已提交
192
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
193
    return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
B
WIP  
Behdad Esfahbod 已提交
194 195
  }

B
Behdad Esfahbod 已提交
196 197
  inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
  {
B
Behdad Esfahbod 已提交
198
    TRACE_SANITIZE (this);
B
WIP  
Behdad Esfahbod 已提交
199 200
    unsigned int len = get_len ();

B
Behdad Esfahbod 已提交
201
    if (!c->check_array (values, get_size (), count)) return_trace (false);
B
WIP  
Behdad Esfahbod 已提交
202

B
Behdad Esfahbod 已提交
203
    if (!has_device ()) return_trace (true);
B
WIP  
Behdad Esfahbod 已提交
204 205

    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
206
      if (!sanitize_value_devices (c, base, values))
B
Behdad Esfahbod 已提交
207
        return_trace (false);
B
WIP  
Behdad Esfahbod 已提交
208 209 210
      values += len;
    }

B
Behdad Esfahbod 已提交
211
    return_trace (true);
B
WIP  
Behdad Esfahbod 已提交
212 213
  }

B
Behdad Esfahbod 已提交
214
  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
B
Behdad Esfahbod 已提交
215 216
  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 已提交
217
    TRACE_SANITIZE (this);
B
WIP  
Behdad Esfahbod 已提交
218

B
Behdad Esfahbod 已提交
219
    if (!has_device ()) return_trace (true);
B
WIP  
Behdad Esfahbod 已提交
220 221

    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
222
      if (!sanitize_value_devices (c, base, values))
B
Behdad Esfahbod 已提交
223
        return_trace (false);
B
WIP  
Behdad Esfahbod 已提交
224 225 226
      values += stride;
    }

B
Behdad Esfahbod 已提交
227
    return_trace (true);
B
WIP  
Behdad Esfahbod 已提交
228
  }
B
Behdad Esfahbod 已提交
229 230 231
};


B
Behdad Esfahbod 已提交
232 233
struct AnchorFormat1
{
234
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
B
Behdad Esfahbod 已提交
235 236
			  hb_position_t *x, hb_position_t *y) const
  {
B
Minor  
Behdad Esfahbod 已提交
237 238
      *x = font->em_scale_x (xCoordinate);
      *y = font->em_scale_y (yCoordinate);
B
Behdad Esfahbod 已提交
239 240
  }

B
Behdad Esfahbod 已提交
241 242
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
243
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
244
    return_trace (c->check_struct (this));
B
Behdad Esfahbod 已提交
245 246
  }

247
  protected:
B
Behdad Esfahbod 已提交
248 249 250
  USHORT	format;			/* Format identifier--format = 1 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
251 252
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
253 254
};

B
Behdad Esfahbod 已提交
255 256
struct AnchorFormat2
{
257
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
258 259
			  hb_position_t *x, hb_position_t *y) const
  {
260 261
      unsigned int x_ppem = font->x_ppem;
      unsigned int y_ppem = font->y_ppem;
B
Behdad Esfahbod 已提交
262
      hb_position_t cx, cy;
K
Konstantin Ritt 已提交
263
      hb_bool_t ret;
B
Behdad Esfahbod 已提交
264

K
Konstantin Ritt 已提交
265 266 267 268
      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 已提交
269 270
  }

B
Behdad Esfahbod 已提交
271 272
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
273
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
274
    return_trace (c->check_struct (this));
B
Behdad Esfahbod 已提交
275 276
  }

277
  protected:
B
Behdad Esfahbod 已提交
278 279 280 281
  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 */
282 283
  public:
  DEFINE_SIZE_STATIC (8);
B
Behdad Esfahbod 已提交
284 285
};

B
Behdad Esfahbod 已提交
286 287
struct AnchorFormat3
{
288
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
B
Behdad Esfahbod 已提交
289 290
			  hb_position_t *x, hb_position_t *y) const
  {
B
Minor  
Behdad Esfahbod 已提交
291 292
      *x = font->em_scale_x (xCoordinate);
      *y = font->em_scale_y (yCoordinate);
293

294 295 296 297
      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 已提交
298 299
  }

B
Behdad Esfahbod 已提交
300 301
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
302
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
303
    return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
B
Behdad Esfahbod 已提交
304 305
  }

306
  protected:
B
Behdad Esfahbod 已提交
307 308 309 310 311 312 313 314 315 316 317
  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) */
318 319
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
320 321
};

B
Behdad Esfahbod 已提交
322 323
struct Anchor
{
324
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
325 326
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
327 328
    *x = *y = 0;
    switch (u.format) {
329 330 331 332
    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 已提交
333 334 335
    }
  }

B
Behdad Esfahbod 已提交
336 337
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
338
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
339
    if (!u.format.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
340
    switch (u.format) {
B
Behdad Esfahbod 已提交
341 342 343 344
    case 1: return_trace (u.format1.sanitize (c));
    case 2: return_trace (u.format2.sanitize (c));
    case 3: return_trace (u.format3.sanitize (c));
    default:return_trace (true);
B
Behdad Esfahbod 已提交
345 346 347
    }
  }

348
  protected:
B
Behdad Esfahbod 已提交
349 350
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
351 352 353
  AnchorFormat1		format1;
  AnchorFormat2		format2;
  AnchorFormat3		format3;
B
Behdad Esfahbod 已提交
354
  } u;
B
Behdad Esfahbod 已提交
355
  public:
B
Behdad Esfahbod 已提交
356
  DEFINE_SIZE_UNION (2, format);
B
Behdad Esfahbod 已提交
357 358 359
};


360 361
struct AnchorMatrix
{
362 363
  inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
    *found = false;
364
    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
365 366
    *found = !matrixZ[row * cols + col].is_null ();
    return this+matrixZ[row * cols + col];
367 368
  }

B
Behdad Esfahbod 已提交
369 370
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
  {
B
Behdad Esfahbod 已提交
371
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
372 373
    if (!c->check_struct (this)) return_trace (false);
    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
374
    unsigned int count = rows * cols;
B
Behdad Esfahbod 已提交
375
    if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
376
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
377 378
      if (!matrixZ[i].sanitize (c, this)) return_trace (false);
    return_trace (true);
379 380 381
  }

  USHORT	rows;			/* Number of rows */
382
  protected:
383
  OffsetTo<Anchor>
384
		matrixZ[VAR];		/* Matrix of offsets to Anchor tables--
385
					 * from beginning of AnchorMatrix table */
B
Behdad Esfahbod 已提交
386
  public:
387
  DEFINE_SIZE_ARRAY (2, matrixZ);
388 389 390
};


B
Behdad Esfahbod 已提交
391 392
struct MarkRecord
{
393
  friend struct MarkArray;
B
Behdad Esfahbod 已提交
394

B
Behdad Esfahbod 已提交
395 396
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
B
Behdad Esfahbod 已提交
397
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
398
    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
399 400
  }

401
  protected:
B
Behdad Esfahbod 已提交
402 403 404 405
  USHORT	klass;			/* Class defined for this mark */
  OffsetTo<Anchor>
		markAnchor;		/* Offset to Anchor table--from
					 * beginning of MarkArray table */
B
Behdad Esfahbod 已提交
406 407
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
408 409
};

B
Behdad Esfahbod 已提交
410
struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
B
Behdad Esfahbod 已提交
411
{
B
Behdad Esfahbod 已提交
412
  inline bool apply (hb_apply_context_t *c,
413 414 415 416
		     unsigned int mark_index, unsigned int glyph_index,
		     const AnchorMatrix &anchors, unsigned int class_count,
		     unsigned int glyph_pos) const
  {
B
Behdad Esfahbod 已提交
417
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
418
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
419
    const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
420 421 422
    unsigned int mark_class = record.klass;

    const Anchor& mark_anchor = this + record.markAnchor;
423 424 425 426
    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. */
B
Behdad Esfahbod 已提交
427
    if (unlikely (!found)) return_trace (false);
428 429 430

    hb_position_t mark_x, mark_y, base_x, base_y;

B
Behdad Esfahbod 已提交
431 432
    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);
433

B
Behdad Esfahbod 已提交
434
    hb_glyph_position_t &o = buffer->cur_pos();
B
Behdad Esfahbod 已提交
435 436
    o.x_offset = base_x - mark_x;
    o.y_offset = base_y - mark_y;
437
    o.attach_type() = ATTACH_TYPE_MARK;
438
    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
439
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
    {
      unsigned int i = buffer->idx;
      unsigned int j = glyph_pos;
      hb_glyph_position_t *pos = buffer->pos;
      assert (j < i);
      if (HB_DIRECTION_IS_FORWARD (c->direction))
	for (unsigned int k = j; k < i; k++) {
	  pos[i].x_offset -= pos[k].x_advance;
	  pos[i].y_offset -= pos[k].y_advance;
	}
      else
	for (unsigned int k = j + 1; k < i + 1; k++) {
	  pos[i].x_offset += pos[k].x_advance;
	  pos[i].y_offset += pos[k].y_advance;
	}
    }
456

B
Behdad Esfahbod 已提交
457
    buffer->idx++;
B
Behdad Esfahbod 已提交
458
    return_trace (true);
459
  }
B
Behdad Esfahbod 已提交
460

B
Behdad Esfahbod 已提交
461 462
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
463
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
464
    return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
B
Behdad Esfahbod 已提交
465
  }
B
Behdad Esfahbod 已提交
466 467 468 469 470
};


/* Lookups */

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

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

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

491
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
492
			     values, buffer->cur_pos());
493

B
Behdad Esfahbod 已提交
494
    buffer->idx++;
B
Behdad Esfahbod 已提交
495
    return_trace (true);
B
Behdad Esfahbod 已提交
496 497
  }

B
Behdad Esfahbod 已提交
498 499
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
500
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
501 502 503
    return_trace (c->check_struct (this) &&
		  coverage.sanitize (c, this) &&
		  valueFormat.sanitize_value (c, this, values));
B
Behdad Esfahbod 已提交
504 505
  }

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

B
Behdad Esfahbod 已提交
520 521
struct SinglePosFormat2
{
522 523 524
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
525
    (this+coverage).add_coverage (c->input);
526 527
  }

528 529 530 531 532
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
533
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
534
  {
B
Behdad Esfahbod 已提交
535
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
536 537
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
538
    if (likely (index == NOT_COVERED)) return_trace (false);
539

B
Behdad Esfahbod 已提交
540
    if (likely (index >= valueCount)) return_trace (false);
541

542
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
543
			     &values[index * valueFormat.get_len ()],
B
Behdad Esfahbod 已提交
544
			     buffer->cur_pos());
545

B
Behdad Esfahbod 已提交
546
    buffer->idx++;
B
Behdad Esfahbod 已提交
547
    return_trace (true);
B
Behdad Esfahbod 已提交
548 549
  }

B
Behdad Esfahbod 已提交
550 551
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
552
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
553 554 555
    return_trace (c->check_struct (this) &&
		  coverage.sanitize (c, this) &&
		  valueFormat.sanitize_values (c, this, values, valueCount));
B
Behdad Esfahbod 已提交
556 557
  }

558
  protected:
B
Behdad Esfahbod 已提交
559 560 561 562
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
563
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
564 565 566 567
					 * ValueRecord */
  USHORT	valueCount;		/* Number of ValueRecords */
  ValueRecord	values;			/* Array of ValueRecords--positioning
					 * values applied to glyphs */
B
Behdad Esfahbod 已提交
568
  public:
569
  DEFINE_SIZE_ARRAY (8, values);
B
Behdad Esfahbod 已提交
570 571
};

B
Behdad Esfahbod 已提交
572 573
struct SinglePos
{
574
  template <typename context_t>
575
  inline typename context_t::return_t dispatch (context_t *c) const
576
  {
577
    TRACE_DISPATCH (this, u.format);
578
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
579
    switch (u.format) {
B
Behdad Esfahbod 已提交
580 581 582
    case 1: return_trace (c->dispatch (u.format1));
    case 2: return_trace (c->dispatch (u.format2));
    default:return_trace (c->default_return_value ());
583 584 585
    }
  }

586
  protected:
B
Behdad Esfahbod 已提交
587 588
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
589 590
  SinglePosFormat1	format1;
  SinglePosFormat2	format2;
B
Behdad Esfahbod 已提交
591 592 593 594
  } u;
};


B
Behdad Esfahbod 已提交
595 596
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
597
  friend struct PairSet;
B
Behdad Esfahbod 已提交
598

599
  protected:
B
Behdad Esfahbod 已提交
600 601 602 603 604
  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 已提交
605
  public:
606
  DEFINE_SIZE_ARRAY (2, values);
B
Behdad Esfahbod 已提交
607 608
};

B
Behdad Esfahbod 已提交
609 610
struct PairSet
{
B
Behdad Esfahbod 已提交
611 612
  friend struct PairPosFormat1;

613 614 615 616 617 618 619 620
  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);

621
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
622 623 624
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
    {
B
Minor  
Behdad Esfahbod 已提交
625
      c->input->add (record->secondGlyph);
626 627 628 629
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }
  }

B
Behdad Esfahbod 已提交
630
  inline bool apply (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
631 632 633
		     const ValueFormat *valueFormats,
		     unsigned int pos) const
  {
B
Behdad Esfahbod 已提交
634
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
635
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
636 637 638 639
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);

640
    const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
641
    unsigned int count = len;
642 643 644

    /* Hand-coded bsearch. */
    if (unlikely (!count))
B
Behdad Esfahbod 已提交
645
      return_trace (false);
646 647 648
    hb_codepoint_t x = buffer->info[pos].codepoint;
    int min = 0, max = (int) count - 1;
    while (min <= max)
B
Behdad Esfahbod 已提交
649
    {
650 651 652 653 654 655 656 657
      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 已提交
658
      {
659
	valueFormats[0].apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
660
				     &record->values[0], buffer->cur_pos());
661
	valueFormats[1].apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
662
				     &record->values[len1], buffer->pos[pos]);
B
Behdad Esfahbod 已提交
663 664
	if (len2)
	  pos++;
B
Behdad Esfahbod 已提交
665
	buffer->idx = pos;
B
Behdad Esfahbod 已提交
666
	return_trace (true);
B
Behdad Esfahbod 已提交
667 668 669
      }
    }

B
Behdad Esfahbod 已提交
670
    return_trace (false);
B
Behdad Esfahbod 已提交
671 672 673
  }

  struct sanitize_closure_t {
B
Behdad Esfahbod 已提交
674 675
    const void *base;
    const ValueFormat *valueFormats;
B
Behdad Esfahbod 已提交
676 677 678 679
    unsigned int len1; /* valueFormats[0].get_len() */
    unsigned int stride; /* 1 + len1 + len2 */
  };

B
Behdad Esfahbod 已提交
680 681
  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
  {
B
Behdad Esfahbod 已提交
682
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
683
    if (!(c->check_struct (this)
B
Behdad Esfahbod 已提交
684
       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false);
B
Behdad Esfahbod 已提交
685 686

    unsigned int count = len;
B
Behdad Esfahbod 已提交
687
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
B
Behdad Esfahbod 已提交
688 689
    return_trace (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 已提交
690 691
  }

692
  protected:
B
Behdad Esfahbod 已提交
693
  USHORT	len;			/* Number of PairValueRecords */
694
  USHORT	arrayZ[VAR];		/* Array of PairValueRecords--ordered
B
Behdad Esfahbod 已提交
695
					 * by GlyphID of the second glyph */
B
Behdad Esfahbod 已提交
696
  public:
697
  DEFINE_SIZE_ARRAY (2, arrayZ);
B
Behdad Esfahbod 已提交
698
};
B
Behdad Esfahbod 已提交
699

B
Behdad Esfahbod 已提交
700 701
struct PairPosFormat1
{
702 703 704
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
705
    (this+coverage).add_coverage (c->input);
706 707 708 709 710
    unsigned int count = pairSet.len;
    for (unsigned int i = 0; i < count; i++)
      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
  }

711 712 713 714 715
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
716
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
717
  {
B
Behdad Esfahbod 已提交
718
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
719 720
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
721
    if (likely (index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
722

723
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
724
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
725
    if (!skippy_iter.next ()) return_trace (false);
B
Behdad Esfahbod 已提交
726

B
Behdad Esfahbod 已提交
727
    return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
B
Behdad Esfahbod 已提交
728 729
  }

B
Behdad Esfahbod 已提交
730 731
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
732
    TRACE_SANITIZE (this);
733

734 735
    if (!c->check_struct (this)) return_trace (false);

736 737
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
B
Behdad Esfahbod 已提交
738 739 740 741 742 743
    PairSet::sanitize_closure_t closure = {
      this,
      &valueFormat1,
      len1,
      1 + len1 + len2
    };
744

745
    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
B
Behdad Esfahbod 已提交
746 747
  }

748
  protected:
B
Behdad Esfahbod 已提交
749 750 751 752
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
753
  ValueFormat	valueFormat1;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
754 755
					 * ValueRecord1--for the first glyph
					 * in the pair--may be zero (0) */
756
  ValueFormat	valueFormat2;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
757 758 759 760 761
					 * ValueRecord2--for the second glyph
					 * in the pair--may be zero (0) */
  OffsetArrayOf<PairSet>
		pairSet;		/* Array of PairSet tables
					 * ordered by Coverage Index */
762
  public:
763
  DEFINE_SIZE_ARRAY (10, pairSet);
B
Behdad Esfahbod 已提交
764 765
};

B
Behdad Esfahbod 已提交
766 767
struct PairPosFormat2
{
768 769 770
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
771
    (this+coverage).add_coverage (c->input);
772 773 774 775

    unsigned int count1 = class1Count;
    const ClassDef &klass1 = this+classDef1;
    for (unsigned int i = 0; i < count1; i++)
B
Minor  
Behdad Esfahbod 已提交
776
      klass1.add_class (c->input, i);
777 778 779 780

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

784 785 786 787 788
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
789
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
790
  {
B
Behdad Esfahbod 已提交
791
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
792 793
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
794
    if (likely (index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
795

796
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
797
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
798
    if (!skippy_iter.next ()) return_trace (false);
B
Behdad Esfahbod 已提交
799 800 801 802 803

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

B
Behdad Esfahbod 已提交
804 805
    unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
B
Behdad Esfahbod 已提交
806
    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
B
Behdad Esfahbod 已提交
807

B
Behdad Esfahbod 已提交
808
    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
809
    valueFormat1.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
810
			      v, buffer->cur_pos());
811
    valueFormat2.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
812
			      v + len1, buffer->pos[skippy_iter.idx]);
B
Behdad Esfahbod 已提交
813

B
Behdad Esfahbod 已提交
814
    buffer->idx = skippy_iter.idx;
B
Behdad Esfahbod 已提交
815
    if (len2)
B
Behdad Esfahbod 已提交
816
      buffer->idx++;
B
Behdad Esfahbod 已提交
817

B
Behdad Esfahbod 已提交
818
    return_trace (true);
B
Behdad Esfahbod 已提交
819 820
  }

B
Behdad Esfahbod 已提交
821 822
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
823
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
824 825 826
    if (!(c->check_struct (this)
       && coverage.sanitize (c, this)
       && classDef1.sanitize (c, this)
B
Behdad Esfahbod 已提交
827
       && classDef2.sanitize (c, this))) return_trace (false);
828

829 830 831
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int stride = len1 + len2;
B
Behdad Esfahbod 已提交
832
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
833
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
B
Behdad Esfahbod 已提交
834 835 836
    return_trace (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 已提交
837
  }
B
Behdad Esfahbod 已提交
838

839
  protected:
B
Behdad Esfahbod 已提交
840 841 842 843
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
844
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
845 846
					 * first glyph of the pair--may be zero
					 * (0) */
847
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
					 * 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 已提交
865
  public:
866
  DEFINE_SIZE_ARRAY (16, values);
B
Behdad Esfahbod 已提交
867 868
};

B
Behdad Esfahbod 已提交
869 870
struct PairPos
{
871
  template <typename context_t>
872
  inline typename context_t::return_t dispatch (context_t *c) const
873
  {
874
    TRACE_DISPATCH (this, u.format);
875
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
876
    switch (u.format) {
B
Behdad Esfahbod 已提交
877 878 879
    case 1: return_trace (c->dispatch (u.format1));
    case 2: return_trace (c->dispatch (u.format2));
    default:return_trace (c->default_return_value ());
880 881 882
    }
  }

883
  protected:
B
Behdad Esfahbod 已提交
884 885
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
886 887
  PairPosFormat1	format1;
  PairPosFormat2	format2;
B
Behdad Esfahbod 已提交
888 889 890 891
  } u;
};


B
Behdad Esfahbod 已提交
892 893
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
894 895
  friend struct CursivePosFormat1;

B
Behdad Esfahbod 已提交
896 897
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
B
Behdad Esfahbod 已提交
898
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
899
    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
900 901
  }

902
  protected:
B
Behdad Esfahbod 已提交
903 904 905 906 907 908 909 910
  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 已提交
911 912
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
913 914
};

915 916 917
static void
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);

B
Behdad Esfahbod 已提交
918 919
struct CursivePosFormat1
{
920 921 922
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
923
    (this+coverage).add_coverage (c->input);
924 925
  }

926 927 928 929 930
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
931
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
932
  {
B
Behdad Esfahbod 已提交
933
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
934
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
935

B
Behdad Esfahbod 已提交
936
    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
B
Behdad Esfahbod 已提交
937
    if (!this_record.exitAnchor) return_trace (false);
938

939
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
940
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
941
    if (!skippy_iter.next ()) return_trace (false);
942

B
Behdad Esfahbod 已提交
943
    const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
B
Behdad Esfahbod 已提交
944
    if (!next_record.entryAnchor) return_trace (false);
B
Behdad Esfahbod 已提交
945

B
Behdad Esfahbod 已提交
946
    unsigned int i = buffer->idx;
B
Behdad Esfahbod 已提交
947
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
948

949
    hb_position_t entry_x, entry_y, exit_x, exit_y;
B
Behdad Esfahbod 已提交
950 951
    (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 已提交
952

B
Behdad Esfahbod 已提交
953
    hb_glyph_position_t *pos = buffer->pos;
B
Behdad Esfahbod 已提交
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 982 983 984 985 986 987 988

    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 已提交
989 990
    }

B
Behdad Esfahbod 已提交
991
    /* Cross-direction adjustment */
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009

    /* We attach child to parent (think graph theory and rooted trees whereas
     * the root stays on baseline and each node aligns itself against its
     * parent.
     *
     * Optimize things for the case of RightToLeft, as that's most common in
     * Arabinc. */
    unsigned int child  = i;
    unsigned int parent = j;
    hb_position_t x_offset = entry_x - exit_x;
    hb_position_t y_offset = entry_y - exit_y;
    if  (!(c->lookup_props & LookupFlag::RightToLeft))
    {
      unsigned int k = child;
      child = parent;
      parent = k;
      x_offset = -x_offset;
      y_offset = -y_offset;
B
Behdad Esfahbod 已提交
1010 1011
    }

1012 1013 1014 1015 1016 1017 1018
    /* If child was already connected to someone else, walk through its old
     * chain and reverse the link direction, such that the whole tree of its
     * previous connection now attaches to new parent.  Watch out for case
     * where new parent is on the path from old chain...
     */
    reverse_cursive_minor_offset (pos, child, c->direction, parent);

1019 1020
    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
    pos[child].attach_chain() = (int) parent - (int) child;
1021
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
1022 1023 1024 1025 1026
    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
      pos[child].y_offset = y_offset;
    else
      pos[child].x_offset = x_offset;

B
Behdad Esfahbod 已提交
1027
    buffer->idx = j;
B
Behdad Esfahbod 已提交
1028
    return_trace (true);
B
Behdad Esfahbod 已提交
1029 1030
  }

B
Behdad Esfahbod 已提交
1031 1032
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1033
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1034
    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
B
Behdad Esfahbod 已提交
1035 1036
  }

1037
  protected:
B
Behdad Esfahbod 已提交
1038 1039 1040 1041 1042 1043 1044
  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 */
1045
  public:
1046
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
B
Behdad Esfahbod 已提交
1047 1048
};

B
Behdad Esfahbod 已提交
1049 1050
struct CursivePos
{
1051
  template <typename context_t>
1052
  inline typename context_t::return_t dispatch (context_t *c) const
1053
  {
1054
    TRACE_DISPATCH (this, u.format);
1055
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1056
    switch (u.format) {
B
Behdad Esfahbod 已提交
1057 1058
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1059 1060 1061
    }
  }

1062
  protected:
B
Behdad Esfahbod 已提交
1063 1064
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1065
  CursivePosFormat1	format1;
B
Behdad Esfahbod 已提交
1066 1067 1068 1069
  } u;
};


1070 1071 1072
typedef AnchorMatrix BaseArray;		/* base-major--
					 * in order of BaseCoverage Index--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1073
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1074

B
Behdad Esfahbod 已提交
1075 1076
struct MarkBasePosFormat1
{
1077 1078 1079
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1080 1081
    (this+markCoverage).add_coverage (c->input);
    (this+baseCoverage).add_coverage (c->input);
1082 1083
  }

1084 1085 1086 1087 1088
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1089
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1090
  {
B
Behdad Esfahbod 已提交
1091
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1092 1093
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1094
    if (likely (mark_index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
1095

B
Behdad Esfahbod 已提交
1096
    /* Now we search backwards for a non-mark glyph */
1097
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1098
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
1099
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1100
    do {
B
Behdad Esfahbod 已提交
1101
      if (!skippy_iter.prev ()) return_trace (false);
1102
      /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
B
Behdad Esfahbod 已提交
1103
      if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
1104 1105
      skippy_iter.reject ();
    } while (1);
1106

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

B
Behdad Esfahbod 已提交
1110
    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
B
Behdad Esfahbod 已提交
1111
    if (base_index == NOT_COVERED) return_trace (false);
B
Behdad Esfahbod 已提交
1112

B
Behdad Esfahbod 已提交
1113
    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
B
Behdad Esfahbod 已提交
1114 1115
  }

B
Behdad Esfahbod 已提交
1116 1117
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1118
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1119 1120 1121 1122 1123
    return_trace (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 已提交
1124 1125
  }

1126
  protected:
B
Behdad Esfahbod 已提交
1127
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1128 1129
  OffsetTo<Coverage>
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
1130
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1131 1132
  OffsetTo<Coverage>
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
1133 1134
					 * beginning of MarkBasePos subtable */
  USHORT	classCount;		/* Number of classes defined for marks */
B
Behdad Esfahbod 已提交
1135 1136
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1137
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1138 1139
  OffsetTo<BaseArray>
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
1140
					 * beginning of MarkBasePos subtable */
1141 1142
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1143 1144
};

B
Behdad Esfahbod 已提交
1145 1146
struct MarkBasePos
{
1147
  template <typename context_t>
1148
  inline typename context_t::return_t dispatch (context_t *c) const
1149
  {
1150
    TRACE_DISPATCH (this, u.format);
1151
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1152
    switch (u.format) {
B
Behdad Esfahbod 已提交
1153 1154
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1155 1156 1157
    }
  }

1158
  protected:
B
Behdad Esfahbod 已提交
1159 1160
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1161
  MarkBasePosFormat1	format1;
B
Behdad Esfahbod 已提交
1162 1163 1164 1165
  } u;
};


1166 1167 1168
typedef AnchorMatrix LigatureAttach;	/* component-major--
					 * in order of writing direction--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1169
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1170

1171
typedef OffsetListOf<LigatureAttach> LigatureArray;
B
Behdad Esfahbod 已提交
1172
					/* Array of LigatureAttach
B
Behdad Esfahbod 已提交
1173 1174 1175
					 * tables ordered by
					 * LigatureCoverage Index */

B
Behdad Esfahbod 已提交
1176 1177
struct MarkLigPosFormat1
{
1178 1179 1180
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1181 1182
    (this+markCoverage).add_coverage (c->input);
    (this+ligatureCoverage).add_coverage (c->input);
1183 1184
  }

1185 1186 1187 1188 1189
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1190
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1191
  {
B
Behdad Esfahbod 已提交
1192
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1193 1194
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1195
    if (likely (mark_index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
1196

B
Behdad Esfahbod 已提交
1197
    /* Now we search backwards for a non-mark glyph */
1198
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1199
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
1200
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
B
Behdad Esfahbod 已提交
1201
    if (!skippy_iter.prev ()) return_trace (false);
1202

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

B
Behdad Esfahbod 已提交
1206
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
1207
    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
B
Behdad Esfahbod 已提交
1208
    if (lig_index == NOT_COVERED) return_trace (false);
B
Behdad Esfahbod 已提交
1209 1210

    const LigatureArray& lig_array = this+ligatureArray;
1211
    const LigatureAttach& lig_attach = lig_array[lig_index];
1212 1213

    /* Find component to attach to */
B
Behdad Esfahbod 已提交
1214
    unsigned int comp_count = lig_attach.rows;
B
Behdad Esfahbod 已提交
1215
    if (unlikely (!comp_count)) return_trace (false);
1216

B
Behdad Esfahbod 已提交
1217 1218 1219 1220
    /* 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 已提交
1221
    unsigned int comp_index;
B
Behdad Esfahbod 已提交
1222 1223 1224
    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 已提交
1225
    if (lig_id && lig_id == mark_id && mark_comp > 0)
B
Behdad Esfahbod 已提交
1226
      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
B
Behdad Esfahbod 已提交
1227
    else
B
Behdad Esfahbod 已提交
1228
      comp_index = comp_count - 1;
B
Behdad Esfahbod 已提交
1229

B
Behdad Esfahbod 已提交
1230
    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
B
Behdad Esfahbod 已提交
1231 1232
  }

B
Behdad Esfahbod 已提交
1233 1234
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1235
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1236 1237 1238 1239 1240
    return_trace (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 已提交
1241 1242
  }

1243
  protected:
B
Behdad Esfahbod 已提交
1244
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1245 1246
  OffsetTo<Coverage>
		markCoverage;		/* Offset to Mark Coverage table--from
B
Behdad Esfahbod 已提交
1247
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1248 1249
  OffsetTo<Coverage>
		ligatureCoverage;	/* Offset to Ligature Coverage
B
Behdad Esfahbod 已提交
1250 1251 1252
					 * table--from beginning of MarkLigPos
					 * subtable */
  USHORT	classCount;		/* Number of defined mark classes */
B
Behdad Esfahbod 已提交
1253 1254
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1255
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1256 1257
  OffsetTo<LigatureArray>
		ligatureArray;		/* Offset to LigatureArray table--from
B
Behdad Esfahbod 已提交
1258
					 * beginning of MarkLigPos subtable */
1259 1260
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1261 1262
};

B
Behdad Esfahbod 已提交
1263 1264
struct MarkLigPos
{
1265
  template <typename context_t>
1266
  inline typename context_t::return_t dispatch (context_t *c) const
1267
  {
1268
    TRACE_DISPATCH (this, u.format);
1269
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1270
    switch (u.format) {
B
Behdad Esfahbod 已提交
1271 1272
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1273 1274 1275
    }
  }

1276
  protected:
B
Behdad Esfahbod 已提交
1277 1278
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1279
  MarkLigPosFormat1	format1;
B
Behdad Esfahbod 已提交
1280 1281 1282 1283
  } u;
};


1284 1285 1286 1287
typedef AnchorMatrix Mark2Array;	/* mark2-major--
					 * in order of Mark2Coverage Index--,
					 * mark1-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1288

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

1298 1299 1300 1301 1302
  inline const Coverage &get_coverage (void) const
  {
    return this+mark1Coverage;
  }

B
Behdad Esfahbod 已提交
1303
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1304
  {
B
Behdad Esfahbod 已提交
1305
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1306 1307
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1308
    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
1309 1310

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

B
Behdad Esfahbod 已提交
1316
    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
B
Behdad Esfahbod 已提交
1317

B
Behdad Esfahbod 已提交
1318 1319
    unsigned int j = skippy_iter.idx;

B
Behdad Esfahbod 已提交
1320 1321 1322 1323
    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]);
1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337

    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. */
B
Behdad Esfahbod 已提交
1338
    return_trace (false);
B
Behdad Esfahbod 已提交
1339

1340
    good:
B
Behdad Esfahbod 已提交
1341
    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
B
Behdad Esfahbod 已提交
1342
    if (mark2_index == NOT_COVERED) return_trace (false);
B
Behdad Esfahbod 已提交
1343

B
Behdad Esfahbod 已提交
1344
    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
B
Behdad Esfahbod 已提交
1345 1346
  }

B
Behdad Esfahbod 已提交
1347 1348
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1349
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1350 1351 1352 1353 1354
    return_trace (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 已提交
1355 1356
  }

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

B
Behdad Esfahbod 已提交
1378 1379
struct MarkMarkPos
{
1380
  template <typename context_t>
1381
  inline typename context_t::return_t dispatch (context_t *c) const
1382
  {
1383
    TRACE_DISPATCH (this, u.format);
1384
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1385
    switch (u.format) {
B
Behdad Esfahbod 已提交
1386 1387
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1388 1389 1390
    }
  }

1391
  protected:
B
Behdad Esfahbod 已提交
1392 1393
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1394
  MarkMarkPosFormat1	format1;
B
Behdad Esfahbod 已提交
1395 1396 1397 1398
  } u;
};


B
Minor  
Behdad Esfahbod 已提交
1399
struct ContextPos : Context {};
B
Behdad Esfahbod 已提交
1400

B
Minor  
Behdad Esfahbod 已提交
1401
struct ChainContextPos : ChainContext {};
B
Behdad Esfahbod 已提交
1402

B
Behdad Esfahbod 已提交
1403
struct ExtensionPos : Extension<ExtensionPos>
B
Behdad Esfahbod 已提交
1404
{
1405
  typedef struct PosLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
1406 1407 1408
};


1409

B
Behdad Esfahbod 已提交
1410 1411 1412 1413 1414
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
1415 1416
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
1417 1418
  friend struct PosLookup;

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

1431
  template <typename context_t>
1432
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1433
  {
1434
    TRACE_DISPATCH (this, lookup_type);
1435
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1436
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
    case Single:		return_trace (u.single.dispatch (c));
    case Pair:			return_trace (u.pair.dispatch (c));
    case Cursive:		return_trace (u.cursive.dispatch (c));
    case MarkBase:		return_trace (u.markBase.dispatch (c));
    case MarkLig:		return_trace (u.markLig.dispatch (c));
    case MarkMark:		return_trace (u.markMark.dispatch (c));
    case Context:		return_trace (u.context.dispatch (c));
    case ChainContext:		return_trace (u.chainContext.dispatch (c));
    case Extension:		return_trace (u.extension.dispatch (c));
    default:			return_trace (c->default_return_value ());
1447
    }
1448 1449
  }

1450
  protected:
B
Behdad Esfahbod 已提交
1451
  union {
B
Minor  
Behdad Esfahbod 已提交
1452
  USHORT		sub_format;
B
Behdad Esfahbod 已提交
1453 1454 1455 1456 1457 1458
  SinglePos		single;
  PairPos		pair;
  CursivePos		cursive;
  MarkBasePos		markBase;
  MarkLigPos		markLig;
  MarkMarkPos		markMark;
1459
  ContextPos		context;
B
Behdad Esfahbod 已提交
1460 1461
  ChainContextPos	chainContext;
  ExtensionPos		extension;
B
Behdad Esfahbod 已提交
1462
  } u;
B
Behdad Esfahbod 已提交
1463
  public:
B
Minor  
Behdad Esfahbod 已提交
1464
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1465 1466 1467
};


B
Behdad Esfahbod 已提交
1468 1469
struct PosLookup : Lookup
{
1470
  inline const PosLookupSubTable& get_subtable (unsigned int i) const
1471
  { return Lookup::get_subtable<PosLookupSubTable> (i); }
B
Behdad Esfahbod 已提交
1472

B
Behdad Esfahbod 已提交
1473 1474 1475 1476 1477
  inline bool is_reverse (void) const
  {
    return false;
  }

B
Behdad Esfahbod 已提交
1478 1479 1480
  inline bool apply (hb_apply_context_t *c) const
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1481
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1482 1483
  }

B
Behdad Esfahbod 已提交
1484
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1485 1486
  {
    TRACE_COLLECT_GLYPHS (this);
B
Behdad Esfahbod 已提交
1487
    return_trace (dispatch (c));
1488 1489
  }

B
Behdad Esfahbod 已提交
1490 1491 1492
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1493 1494
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1495 1496
  }

1497 1498
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);

B
Behdad Esfahbod 已提交
1499 1500 1501 1502 1503
  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
1504
  { return Lookup::dispatch<PosLookupSubTable> (c); }
B
Behdad Esfahbod 已提交
1505

B
Behdad Esfahbod 已提交
1506 1507
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1508
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1509 1510
    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1511
  }
B
Behdad Esfahbod 已提交
1512 1513
};

B
Behdad Esfahbod 已提交
1514
typedef OffsetListOf<PosLookup> PosLookupList;
B
Behdad Esfahbod 已提交
1515 1516

/*
B
Behdad Esfahbod 已提交
1517
 * GPOS -- The Glyph Positioning Table
B
Behdad Esfahbod 已提交
1518 1519
 */

B
Behdad Esfahbod 已提交
1520 1521
struct GPOS : GSUBGPOS
{
1522
  static const hb_tag_t tableTag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1523

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

1527
  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1528 1529
  static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
  static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
B
Behdad Esfahbod 已提交
1530

B
Behdad Esfahbod 已提交
1531 1532
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1533
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1534
    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
B
Behdad Esfahbod 已提交
1535
    const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
B
Behdad Esfahbod 已提交
1536
    return_trace (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1537
  }
1538 1539
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
1540 1541
};

B
Behdad Esfahbod 已提交
1542

1543 1544 1545
static void
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
{
1546 1547
  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
1548 1549
    return;

1550
  pos[i].attach_chain() = 0;
1551

1552
  unsigned int j = (int) i + chain;
B
Behdad Esfahbod 已提交
1553

1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564
  /* Stop if we see new parent in the chain. */
  if (j == new_parent)
    return;

  reverse_cursive_minor_offset (pos, j, direction, new_parent);

  if (HB_DIRECTION_IS_HORIZONTAL (direction))
    pos[j].y_offset = -pos[i].y_offset;
  else
    pos[j].x_offset = -pos[i].x_offset;

1565 1566
  pos[j].attach_chain() = -chain;
  pos[j].attach_type() = type;
1567
}
B
Behdad Esfahbod 已提交
1568
static void
1569
propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
B
Behdad Esfahbod 已提交
1570
{
1571 1572
  /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
   * offset of glyph they are attached to. */
1573
  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
1574
  if (likely (!chain))
B
Behdad Esfahbod 已提交
1575
    return;
B
Behdad Esfahbod 已提交
1576

1577
  unsigned int j = (int) i + chain;
B
Behdad Esfahbod 已提交
1578

1579
  pos[i].attach_chain() = 0;
1580

1581
  propagate_attachment_offsets (pos, j, direction);
1582

1583
  assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
B
Behdad Esfahbod 已提交
1584

1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
  if (type & ATTACH_TYPE_CURSIVE)
  {
    if (HB_DIRECTION_IS_HORIZONTAL (direction))
      pos[i].y_offset += pos[j].y_offset;
    else
      pos[i].x_offset += pos[j].x_offset;
  }
  else /*if (type & ATTACH_TYPE_MARK)*/
  {
    pos[i].x_offset += pos[j].x_offset;
    pos[i].y_offset += pos[j].y_offset;
  }
B
Behdad Esfahbod 已提交
1597 1598
}

B
Behdad Esfahbod 已提交
1599
void
1600
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1601
{
1602 1603
  unsigned int count = buffer->len;
  for (unsigned int i = 0; i < count; i++)
1604
    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
B
Behdad Esfahbod 已提交
1605 1606
}

B
Behdad Esfahbod 已提交
1607
void
1608 1609 1610 1611 1612 1613 1614
GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
{
  //_hb_buffer_assert_gsubgpos_vars (buffer);
}

void
GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1615
{
1616 1617
  _hb_buffer_assert_gsubgpos_vars (buffer);

1618 1619
  unsigned int len;
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
B
Behdad Esfahbod 已提交
1620 1621 1622
  hb_direction_t direction = buffer->props.direction;

  /* Handle attachments */
1623 1624
  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
    for (unsigned int i = 0; i < len; i++)
1625
      propagate_attachment_offsets (pos, i, direction);
B
Behdad Esfahbod 已提交
1626 1627
}

B
Behdad Esfahbod 已提交
1628 1629 1630

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

1631
template <typename context_t>
1632
/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1633 1634 1635
{
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
  const PosLookup &l = gpos.get_lookup (lookup_index);
1636
  return l.dispatch (c);
1637 1638
}

1639
/*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1640
{
1641
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
B
Behdad Esfahbod 已提交
1642
  const PosLookup &l = gpos.get_lookup (lookup_index);
1643
  unsigned int saved_lookup_props = c->lookup_props;
1644 1645 1646
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1647
  bool ret = l.dispatch (c);
1648
  c->set_lookup_index (saved_lookup_index);
1649
  c->set_lookup_props (saved_lookup_props);
1650
  return ret;
B
Behdad Esfahbod 已提交
1651 1652 1653
}


1654
#undef attach_chain
1655
#undef attach_type
B
Behdad Esfahbod 已提交
1656 1657


B
Behdad Esfahbod 已提交
1658
} /* namespace OT */
1659

B
Behdad Esfahbod 已提交
1660

1661
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */