hb-ot-layout-gpos-table.hh 51.1 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3
 * Copyright © 2010,2012,2013  Google, Inc.
B
Behdad Esfahbod 已提交
4
 *
B
Behdad Esfahbod 已提交
5
 *  This is part of HarfBuzz, a text shaping library.
B
Behdad Esfahbod 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Red Hat Author(s): Behdad Esfahbod
26
 * Google Author(s): Behdad Esfahbod
B
Behdad Esfahbod 已提交
27 28
 */

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

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

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

B
Behdad Esfahbod 已提交
37

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


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

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

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

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

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

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

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

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

    if (!format) return;

B
Minor  
Behdad Esfahbod 已提交
109 110
    if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++));
    if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++));
111
    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
  inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
B
WIP  
Behdad Esfahbod 已提交
150 151 152 153 154 155 156
    unsigned int format = *this;

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

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

    return true;
  }

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

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

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

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

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

191
    if (!has_device ()) return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
192 193

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

199
    return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
200 201
  }

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

206
    if (!has_device ()) return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
207 208

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

214
    return TRACE_RETURN (true);
B
WIP  
Behdad Esfahbod 已提交
215
  }
B
Behdad Esfahbod 已提交
216 217 218
};


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

B
Behdad Esfahbod 已提交
228
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
229
    TRACE_SANITIZE (this);
230
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
231 232
  }

233
  protected:
B
Behdad Esfahbod 已提交
234 235 236
  USHORT	format;			/* Format identifier--format = 1 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
237 238
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
239 240
};

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

K
Konstantin Ritt 已提交
251 252 253 254
      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 已提交
255 256
  }

B
Behdad Esfahbod 已提交
257
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
258
    TRACE_SANITIZE (this);
259
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
260 261
  }

262
  protected:
B
Behdad Esfahbod 已提交
263 264 265 266
  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 */
267 268
  public:
  DEFINE_SIZE_STATIC (8);
B
Behdad Esfahbod 已提交
269 270
};

B
Behdad Esfahbod 已提交
271 272
struct AnchorFormat3
{
273
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
B
Behdad Esfahbod 已提交
274 275
			  hb_position_t *x, hb_position_t *y) const
  {
B
Minor  
Behdad Esfahbod 已提交
276 277
      *x = font->em_scale_x (xCoordinate);
      *y = font->em_scale_y (yCoordinate);
278

279 280 281 282
      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 已提交
283 284
  }

B
Behdad Esfahbod 已提交
285
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
286
    TRACE_SANITIZE (this);
287
    return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
B
Behdad Esfahbod 已提交
288 289
  }

290
  protected:
B
Behdad Esfahbod 已提交
291 292 293 294 295 296 297 298 299 300 301
  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) */
302 303
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
304 305
};

B
Behdad Esfahbod 已提交
306 307
struct Anchor
{
308
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
309 310
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
311 312
    *x = *y = 0;
    switch (u.format) {
313 314 315 316
    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 已提交
317 318 319
    }
  }

B
Behdad Esfahbod 已提交
320
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
321
    TRACE_SANITIZE (this);
322
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
323
    switch (u.format) {
324 325 326 327
    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 已提交
328 329 330
    }
  }

331
  protected:
B
Behdad Esfahbod 已提交
332 333
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
334 335 336
  AnchorFormat1		format1;
  AnchorFormat2		format2;
  AnchorFormat3		format3;
B
Behdad Esfahbod 已提交
337
  } u;
B
Behdad Esfahbod 已提交
338
  public:
B
Behdad Esfahbod 已提交
339
  DEFINE_SIZE_UNION (2, format);
B
Behdad Esfahbod 已提交
340 341 342
};


343 344
struct AnchorMatrix
{
345 346
  inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
    *found = false;
347
    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
348
    *found = !matrix[row * cols + col].is_null ();
349 350 351
    return this+matrix[row * cols + col];
  }

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

  USHORT	rows;			/* Number of rows */
364
  protected:
365
  OffsetTo<Anchor>
B
Behdad Esfahbod 已提交
366
		matrix[VAR];		/* Matrix of offsets to Anchor tables--
367
					 * from beginning of AnchorMatrix table */
B
Behdad Esfahbod 已提交
368
  public:
369
  DEFINE_SIZE_ARRAY (2, matrix);
370 371 372
};


B
Behdad Esfahbod 已提交
373 374
struct MarkRecord
{
375
  friend struct MarkArray;
B
Behdad Esfahbod 已提交
376

B
Behdad Esfahbod 已提交
377
  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
B
Behdad Esfahbod 已提交
378
    TRACE_SANITIZE (this);
379
    return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
380 381
  }

382
  protected:
B
Behdad Esfahbod 已提交
383 384 385 386
  USHORT	klass;			/* Class defined for this mark */
  OffsetTo<Anchor>
		markAnchor;		/* Offset to Anchor table--from
					 * beginning of MarkArray table */
B
Behdad Esfahbod 已提交
387 388
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
389 390
};

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

    const Anchor& mark_anchor = this + record.markAnchor;
404 405 406 407 408
    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);
409 410 411

    hb_position_t mark_x, mark_y, base_x, base_y;

B
Behdad Esfahbod 已提交
412 413
    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);
414

B
Behdad Esfahbod 已提交
415
    hb_glyph_position_t &o = buffer->cur_pos();
B
Behdad Esfahbod 已提交
416 417
    o.x_offset = base_x - mark_x;
    o.y_offset = base_y - mark_y;
B
Behdad Esfahbod 已提交
418
    o.attach_lookback() = buffer->idx - glyph_pos;
419

B
Behdad Esfahbod 已提交
420
    buffer->idx++;
421
    return TRACE_RETURN (true);
422
  }
B
Behdad Esfahbod 已提交
423

B
Behdad Esfahbod 已提交
424
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
425
    TRACE_SANITIZE (this);
426
    return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
B
Behdad Esfahbod 已提交
427
  }
B
Behdad Esfahbod 已提交
428 429 430 431 432
};


/* Lookups */

B
Behdad Esfahbod 已提交
433 434
struct SinglePosFormat1
{
435 436 437
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
438
    (this+coverage).add_coverage (c->input);
439 440
  }

441 442 443 444 445
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
446
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
447
  {
B
Behdad Esfahbod 已提交
448
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
449 450
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
451
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
452

453
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
454
			     values, buffer->cur_pos());
455

B
Behdad Esfahbod 已提交
456
    buffer->idx++;
457
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
458 459
  }

B
Behdad Esfahbod 已提交
460
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
461
    TRACE_SANITIZE (this);
462
    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
B
Behdad Esfahbod 已提交
463 464
  }

465
  protected:
B
Behdad Esfahbod 已提交
466 467 468 469
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
470
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
471 472 473 474
					 * ValueRecord */
  ValueRecord	values;			/* Defines positioning
					 * value(s)--applied to all glyphs in
					 * the Coverage table */
B
Behdad Esfahbod 已提交
475
  public:
476
  DEFINE_SIZE_ARRAY (6, values);
B
Behdad Esfahbod 已提交
477 478
};

B
Behdad Esfahbod 已提交
479 480
struct SinglePosFormat2
{
481 482 483
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
484
    (this+coverage).add_coverage (c->input);
485 486
  }

487 488 489 490 491
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
492
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
493
  {
B
Behdad Esfahbod 已提交
494
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
495 496
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
497
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
498

499
    if (likely (index >= valueCount)) return TRACE_RETURN (false);
500

501
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
502
			     &values[index * valueFormat.get_len ()],
B
Behdad Esfahbod 已提交
503
			     buffer->cur_pos());
504

B
Behdad Esfahbod 已提交
505
    buffer->idx++;
506
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
507 508
  }

B
Behdad Esfahbod 已提交
509
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
510
    TRACE_SANITIZE (this);
511
    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
B
Behdad Esfahbod 已提交
512 513
  }

514
  protected:
B
Behdad Esfahbod 已提交
515 516 517 518
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
519
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
520 521 522 523
					 * ValueRecord */
  USHORT	valueCount;		/* Number of ValueRecords */
  ValueRecord	values;			/* Array of ValueRecords--positioning
					 * values applied to glyphs */
B
Behdad Esfahbod 已提交
524
  public:
525
  DEFINE_SIZE_ARRAY (8, values);
B
Behdad Esfahbod 已提交
526 527
};

B
Behdad Esfahbod 已提交
528 529
struct SinglePos
{
530
  template <typename context_t>
531
  inline typename context_t::return_t dispatch (context_t *c) const
532
  {
533
    TRACE_DISPATCH (this);
534
    switch (u.format) {
535 536
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
B
Behdad Esfahbod 已提交
537
    default:return TRACE_RETURN (c->default_return_value ());
538 539 540
    }
  }

B
Behdad Esfahbod 已提交
541
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
542
    TRACE_SANITIZE (this);
543
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
544
    switch (u.format) {
545 546 547
    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 已提交
548 549 550
    }
  }

551
  protected:
B
Behdad Esfahbod 已提交
552 553
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
554 555
  SinglePosFormat1	format1;
  SinglePosFormat2	format2;
B
Behdad Esfahbod 已提交
556 557 558 559
  } u;
};


B
Behdad Esfahbod 已提交
560 561
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
562
  friend struct PairSet;
B
Behdad Esfahbod 已提交
563

564
  protected:
B
Behdad Esfahbod 已提交
565 566 567 568 569
  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 已提交
570
  public:
571
  DEFINE_SIZE_ARRAY (2, values);
B
Behdad Esfahbod 已提交
572 573
};

B
Behdad Esfahbod 已提交
574 575
struct PairSet
{
B
Behdad Esfahbod 已提交
576 577
  friend struct PairPosFormat1;

578 579 580 581 582 583 584 585 586 587 588 589
  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
			      const ValueFormat *valueFormats) const
  {
    TRACE_COLLECT_GLYPHS (this);
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);

    const PairValueRecord *record = CastP<PairValueRecord> (array);
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
    {
B
Minor  
Behdad Esfahbod 已提交
590
      c->input->add (record->secondGlyph);
591 592 593 594
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }
  }

B
Behdad Esfahbod 已提交
595
  inline bool apply (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
596 597 598
		     const ValueFormat *valueFormats,
		     unsigned int pos) const
  {
B
Behdad Esfahbod 已提交
599
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
600
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
601 602 603 604 605
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);

    const PairValueRecord *record = CastP<PairValueRecord> (array);
606
    unsigned int count = len;
B
Behdad Esfahbod 已提交
607 608
    for (unsigned int i = 0; i < count; i++)
    {
609
      /* TODO bsearch */
B
Behdad Esfahbod 已提交
610
      if (buffer->info[pos].codepoint == record->secondGlyph)
B
Behdad Esfahbod 已提交
611
      {
612
	valueFormats[0].apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
613
				     &record->values[0], buffer->cur_pos());
614
	valueFormats[1].apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
615
				     &record->values[len1], buffer->pos[pos]);
B
Behdad Esfahbod 已提交
616 617
	if (len2)
	  pos++;
B
Behdad Esfahbod 已提交
618
	buffer->idx = pos;
619
	return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
620 621 622 623
      }
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }

624
    return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
625 626 627 628 629 630 631 632 633
  }

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

B
Behdad Esfahbod 已提交
634
  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
B
Behdad Esfahbod 已提交
635
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
636
    if (!(c->check_struct (this)
637
       && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
638 639 640

    unsigned int count = len;
    PairValueRecord *record = CastP<PairValueRecord> (array);
641 642
    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 已提交
643 644
  }

645
  protected:
B
Behdad Esfahbod 已提交
646
  USHORT	len;			/* Number of PairValueRecords */
647
  USHORT	array[VAR];		/* Array of PairValueRecords--ordered
B
Behdad Esfahbod 已提交
648
					 * by GlyphID of the second glyph */
B
Behdad Esfahbod 已提交
649
  public:
650
  DEFINE_SIZE_ARRAY (2, array);
B
Behdad Esfahbod 已提交
651
};
B
Behdad Esfahbod 已提交
652

B
Behdad Esfahbod 已提交
653 654
struct PairPosFormat1
{
655 656 657
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
658
    (this+coverage).add_coverage (c->input);
659 660 661 662 663
    unsigned int count = pairSet.len;
    for (unsigned int i = 0; i < count; i++)
      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
  }

664 665 666 667 668
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
669
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
670
  {
B
Behdad Esfahbod 已提交
671
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
672 673
    hb_buffer_t *buffer = c->buffer;
    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
674
    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
675

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

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

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

B
Behdad Esfahbod 已提交
684
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
685
    TRACE_SANITIZE (this);
686 687 688

    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
B
Behdad Esfahbod 已提交
689 690 691 692 693 694
    PairSet::sanitize_closure_t closure = {
      this,
      &valueFormat1,
      len1,
      1 + len1 + len2
    };
695

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

699
  protected:
B
Behdad Esfahbod 已提交
700 701 702 703
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
704
  ValueFormat	valueFormat1;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
705 706
					 * ValueRecord1--for the first glyph
					 * in the pair--may be zero (0) */
707
  ValueFormat	valueFormat2;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
708 709 710 711 712
					 * ValueRecord2--for the second glyph
					 * in the pair--may be zero (0) */
  OffsetArrayOf<PairSet>
		pairSet;		/* Array of PairSet tables
					 * ordered by Coverage Index */
713
  public:
714
  DEFINE_SIZE_ARRAY (10, pairSet);
B
Behdad Esfahbod 已提交
715 716
};

B
Behdad Esfahbod 已提交
717 718
struct PairPosFormat2
{
719 720 721
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
722
    /* (this+coverage).add_coverage (c->input); // Don't need this. */
723 724 725 726

    unsigned int count1 = class1Count;
    const ClassDef &klass1 = this+classDef1;
    for (unsigned int i = 0; i < count1; i++)
B
Minor  
Behdad Esfahbod 已提交
727
      klass1.add_class (c->input, i);
728 729 730 731

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

735 736 737 738 739
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
740
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
741
  {
B
Behdad Esfahbod 已提交
742
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
743 744
    hb_buffer_t *buffer = c->buffer;
    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
745
    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
746

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

750
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
751 752 753 754 755

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

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

B
Behdad Esfahbod 已提交
760
    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
761
    valueFormat1.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
762
			      v, buffer->cur_pos());
763
    valueFormat2.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
764
			      v + len1, buffer->pos[skippy_iter.idx]);
B
Behdad Esfahbod 已提交
765

B
Behdad Esfahbod 已提交
766
    buffer->idx = skippy_iter.idx;
B
Behdad Esfahbod 已提交
767
    if (len2)
B
Behdad Esfahbod 已提交
768
      buffer->idx++;
B
Behdad Esfahbod 已提交
769

770
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
771 772
  }

B
Behdad Esfahbod 已提交
773
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
774
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
775 776 777
    if (!(c->check_struct (this)
       && coverage.sanitize (c, this)
       && classDef1.sanitize (c, this)
778
       && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
779

780 781 782
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int stride = len1 + len2;
B
Behdad Esfahbod 已提交
783
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
784
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
785 786 787
    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 已提交
788
  }
B
Behdad Esfahbod 已提交
789

790
  protected:
B
Behdad Esfahbod 已提交
791 792 793 794
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
795
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
796 797
					 * first glyph of the pair--may be zero
					 * (0) */
798
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
					 * 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 已提交
816
  public:
817
  DEFINE_SIZE_ARRAY (16, values);
B
Behdad Esfahbod 已提交
818 819
};

B
Behdad Esfahbod 已提交
820 821
struct PairPos
{
822
  template <typename context_t>
823
  inline typename context_t::return_t dispatch (context_t *c) const
824
  {
825
    TRACE_DISPATCH (this);
826
    switch (u.format) {
827 828
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
B
Behdad Esfahbod 已提交
829
    default:return TRACE_RETURN (c->default_return_value ());
830 831 832
    }
  }

B
Behdad Esfahbod 已提交
833
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
834
    TRACE_SANITIZE (this);
835
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
836
    switch (u.format) {
837 838 839
    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 已提交
840 841 842
    }
  }

843
  protected:
B
Behdad Esfahbod 已提交
844 845
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
846 847
  PairPosFormat1	format1;
  PairPosFormat2	format2;
B
Behdad Esfahbod 已提交
848 849 850 851
  } u;
};


B
Behdad Esfahbod 已提交
852 853
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
854 855
  friend struct CursivePosFormat1;

B
Behdad Esfahbod 已提交
856
  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
B
Behdad Esfahbod 已提交
857
    TRACE_SANITIZE (this);
858
    return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
859 860
  }

861
  protected:
B
Behdad Esfahbod 已提交
862 863 864 865 866 867 868 869
  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 已提交
870 871
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
872 873
};

B
Behdad Esfahbod 已提交
874 875
struct CursivePosFormat1
{
876 877 878
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
879
    (this+coverage).add_coverage (c->input);
880 881
  }

882 883 884 885 886
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
887
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
888
  {
B
Behdad Esfahbod 已提交
889
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
890
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
891 892

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

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

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

901
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
902

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

B
Behdad Esfahbod 已提交
906
    unsigned int i = buffer->idx;
B
Behdad Esfahbod 已提交
907
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
908

909
    hb_position_t entry_x, entry_y, exit_x, exit_y;
B
Behdad Esfahbod 已提交
910 911
    (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 已提交
912

B
Behdad Esfahbod 已提交
913
    hb_glyph_position_t *pos = buffer->pos;
B
Behdad Esfahbod 已提交
914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948

    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 已提交
949 950
    }

B
Behdad Esfahbod 已提交
951 952 953
    /* Cross-direction adjustment */
    if  (c->lookup_props & LookupFlag::RightToLeft) {
      pos[i].cursive_chain() = j - i;
954
      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
B
Behdad Esfahbod 已提交
955
	pos[i].y_offset = entry_y - exit_y;
956
      else
B
Behdad Esfahbod 已提交
957 958 959
	pos[i].x_offset = entry_x - exit_x;
    } else {
      pos[j].cursive_chain() = i - j;
960
      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
B
Behdad Esfahbod 已提交
961
	pos[j].y_offset = exit_y - entry_y;
962
      else
B
Behdad Esfahbod 已提交
963
	pos[j].x_offset = exit_x - entry_x;
B
Behdad Esfahbod 已提交
964 965
    }

B
Behdad Esfahbod 已提交
966
    buffer->idx = j;
967
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
968 969
  }

B
Behdad Esfahbod 已提交
970
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
971
    TRACE_SANITIZE (this);
972
    return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
B
Behdad Esfahbod 已提交
973 974
  }

975
  protected:
B
Behdad Esfahbod 已提交
976 977 978 979 980 981 982
  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 */
983
  public:
984
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
B
Behdad Esfahbod 已提交
985 986
};

B
Behdad Esfahbod 已提交
987 988
struct CursivePos
{
989
  template <typename context_t>
990
  inline typename context_t::return_t dispatch (context_t *c) const
991
  {
992
    TRACE_DISPATCH (this);
993
    switch (u.format) {
994
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
995
    default:return TRACE_RETURN (c->default_return_value ());
996 997 998
    }
  }

B
Behdad Esfahbod 已提交
999
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1000
    TRACE_SANITIZE (this);
1001
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1002
    switch (u.format) {
1003 1004
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1005 1006 1007
    }
  }

1008
  protected:
B
Behdad Esfahbod 已提交
1009 1010
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1011
  CursivePosFormat1	format1;
B
Behdad Esfahbod 已提交
1012 1013 1014 1015
  } u;
};


1016 1017 1018
typedef AnchorMatrix BaseArray;		/* base-major--
					 * in order of BaseCoverage Index--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1019
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1020

B
Behdad Esfahbod 已提交
1021 1022
struct MarkBasePosFormat1
{
1023 1024 1025
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1026 1027
    (this+markCoverage).add_coverage (c->input);
    (this+baseCoverage).add_coverage (c->input);
1028 1029
  }

1030 1031 1032 1033 1034
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1035
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1036
  {
B
Behdad Esfahbod 已提交
1037
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1038 1039
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1040
    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1041 1042

    /* now we search backwards for a non-mark glyph */
B
Behdad Esfahbod 已提交
1043
    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
B
Behdad Esfahbod 已提交
1044
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1045
    do {
B
Behdad Esfahbod 已提交
1046
      if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1047
      /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
B
Behdad Esfahbod 已提交
1048
      if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
1049 1050
      skippy_iter.reject ();
    } while (1);
1051

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

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

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

B
Behdad Esfahbod 已提交
1061
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1062
    TRACE_SANITIZE (this);
1063 1064
    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 已提交
1065 1066
  }

1067
  protected:
B
Behdad Esfahbod 已提交
1068
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1069 1070
  OffsetTo<Coverage>
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
1071
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1072 1073
  OffsetTo<Coverage>
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
1074 1075
					 * beginning of MarkBasePos subtable */
  USHORT	classCount;		/* Number of classes defined for marks */
B
Behdad Esfahbod 已提交
1076 1077
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1078
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1079 1080
  OffsetTo<BaseArray>
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
1081
					 * beginning of MarkBasePos subtable */
1082 1083
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1084 1085
};

B
Behdad Esfahbod 已提交
1086 1087
struct MarkBasePos
{
1088
  template <typename context_t>
1089
  inline typename context_t::return_t dispatch (context_t *c) const
1090
  {
1091
    TRACE_DISPATCH (this);
1092
    switch (u.format) {
1093
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1094
    default:return TRACE_RETURN (c->default_return_value ());
1095 1096 1097
    }
  }

B
Behdad Esfahbod 已提交
1098
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1099
    TRACE_SANITIZE (this);
1100
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1101
    switch (u.format) {
1102 1103
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1104 1105 1106
    }
  }

1107
  protected:
B
Behdad Esfahbod 已提交
1108 1109
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1110
  MarkBasePosFormat1	format1;
B
Behdad Esfahbod 已提交
1111 1112 1113 1114
  } u;
};


1115 1116 1117
typedef AnchorMatrix LigatureAttach;	/* component-major--
					 * in order of writing direction--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1118
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1119

1120
typedef OffsetListOf<LigatureAttach> LigatureArray;
B
Behdad Esfahbod 已提交
1121
					/* Array of LigatureAttach
B
Behdad Esfahbod 已提交
1122 1123 1124
					 * tables ordered by
					 * LigatureCoverage Index */

B
Behdad Esfahbod 已提交
1125 1126
struct MarkLigPosFormat1
{
1127 1128 1129
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1130 1131
    (this+markCoverage).add_coverage (c->input);
    (this+ligatureCoverage).add_coverage (c->input);
1132 1133
  }

1134 1135 1136 1137 1138
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1139
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1140
  {
B
Behdad Esfahbod 已提交
1141
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1142 1143
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1144
    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1145 1146

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

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

B
Behdad Esfahbod 已提交
1154
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
1155
    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
1156
    if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1157 1158

    const LigatureArray& lig_array = this+ligatureArray;
1159
    const LigatureAttach& lig_attach = lig_array[lig_index];
1160 1161

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

B
Behdad Esfahbod 已提交
1165 1166 1167 1168
    /* 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 已提交
1169
    unsigned int comp_index;
B
Behdad Esfahbod 已提交
1170 1171 1172
    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 已提交
1173
    if (lig_id && lig_id == mark_id && mark_comp > 0)
B
Behdad Esfahbod 已提交
1174
      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
B
Behdad Esfahbod 已提交
1175
    else
B
Behdad Esfahbod 已提交
1176
      comp_index = comp_count - 1;
B
Behdad Esfahbod 已提交
1177

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

B
Behdad Esfahbod 已提交
1181
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1182
    TRACE_SANITIZE (this);
1183 1184
    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 已提交
1185 1186
  }

1187
  protected:
B
Behdad Esfahbod 已提交
1188
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1189 1190
  OffsetTo<Coverage>
		markCoverage;		/* Offset to Mark Coverage table--from
B
Behdad Esfahbod 已提交
1191
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1192 1193
  OffsetTo<Coverage>
		ligatureCoverage;	/* Offset to Ligature Coverage
B
Behdad Esfahbod 已提交
1194 1195 1196
					 * table--from beginning of MarkLigPos
					 * subtable */
  USHORT	classCount;		/* Number of defined mark classes */
B
Behdad Esfahbod 已提交
1197 1198
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1199
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1200 1201
  OffsetTo<LigatureArray>
		ligatureArray;		/* Offset to LigatureArray table--from
B
Behdad Esfahbod 已提交
1202
					 * beginning of MarkLigPos subtable */
1203 1204
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1205 1206
};

B
Behdad Esfahbod 已提交
1207 1208
struct MarkLigPos
{
1209
  template <typename context_t>
1210
  inline typename context_t::return_t dispatch (context_t *c) const
1211
  {
1212
    TRACE_DISPATCH (this);
1213
    switch (u.format) {
1214
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1215
    default:return TRACE_RETURN (c->default_return_value ());
1216 1217 1218
    }
  }

B
Behdad Esfahbod 已提交
1219
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1220
    TRACE_SANITIZE (this);
1221
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1222
    switch (u.format) {
1223 1224
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1225 1226 1227
    }
  }

1228
  protected:
B
Behdad Esfahbod 已提交
1229 1230
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1231
  MarkLigPosFormat1	format1;
B
Behdad Esfahbod 已提交
1232 1233 1234 1235
  } u;
};


1236 1237 1238 1239
typedef AnchorMatrix Mark2Array;	/* mark2-major--
					 * in order of Mark2Coverage Index--,
					 * mark1-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1240

B
Behdad Esfahbod 已提交
1241 1242
struct MarkMarkPosFormat1
{
1243 1244 1245
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1246 1247
    (this+mark1Coverage).add_coverage (c->input);
    (this+mark2Coverage).add_coverage (c->input);
1248 1249
  }

1250 1251 1252 1253 1254
  inline const Coverage &get_coverage (void) const
  {
    return this+mark1Coverage;
  }

B
Behdad Esfahbod 已提交
1255
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1256
  {
B
Behdad Esfahbod 已提交
1257
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1258 1259
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
1260
    if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1261 1262

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

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

B
Behdad Esfahbod 已提交
1269 1270
    unsigned int j = skippy_iter.idx;

B
Behdad Esfahbod 已提交
1271 1272 1273 1274
    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]);
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289

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

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

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

B
Behdad Esfahbod 已提交
1298
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1299
    TRACE_SANITIZE (this);
1300 1301 1302
    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 已提交
1303 1304
  }

1305
  protected:
B
Behdad Esfahbod 已提交
1306
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1307 1308
  OffsetTo<Coverage>
		mark1Coverage;		/* Offset to Combining Mark1 Coverage
B
Behdad Esfahbod 已提交
1309 1310
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1311 1312
  OffsetTo<Coverage>
		mark2Coverage;		/* Offset to Combining Mark2 Coverage
B
Behdad Esfahbod 已提交
1313 1314
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1315 1316 1317 1318 1319 1320 1321
  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 */
1322 1323
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1324 1325
};

B
Behdad Esfahbod 已提交
1326 1327
struct MarkMarkPos
{
1328
  template <typename context_t>
1329
  inline typename context_t::return_t dispatch (context_t *c) const
1330
  {
1331
    TRACE_DISPATCH (this);
1332
    switch (u.format) {
1333
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1334
    default:return TRACE_RETURN (c->default_return_value ());
1335 1336 1337
    }
  }

B
Behdad Esfahbod 已提交
1338
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1339
    TRACE_SANITIZE (this);
1340
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1341
    switch (u.format) {
1342 1343
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1344 1345 1346
    }
  }

1347
  protected:
B
Behdad Esfahbod 已提交
1348 1349
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1350
  MarkMarkPosFormat1	format1;
B
Behdad Esfahbod 已提交
1351 1352 1353 1354
  } u;
};


B
Minor  
Behdad Esfahbod 已提交
1355
struct ContextPos : Context {};
B
Behdad Esfahbod 已提交
1356

B
Minor  
Behdad Esfahbod 已提交
1357
struct ChainContextPos : ChainContext {};
B
Behdad Esfahbod 已提交
1358

B
Behdad Esfahbod 已提交
1359
struct ExtensionPos : Extension<ExtensionPos>
B
Behdad Esfahbod 已提交
1360
{
1361
  typedef struct PosLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
1362 1363 1364
};


1365

B
Behdad Esfahbod 已提交
1366 1367 1368 1369 1370
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
1371 1372
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
1373 1374
  friend struct PosLookup;

B
Behdad Esfahbod 已提交
1375
  enum Type {
1376 1377 1378 1379 1380 1381 1382 1383
    Single		= 1,
    Pair		= 2,
    Cursive		= 3,
    MarkBase		= 4,
    MarkLig		= 5,
    MarkMark		= 6,
    Context		= 7,
    ChainContext	= 8,
1384
    Extension		= 9
1385 1386
  };

1387
  template <typename context_t>
1388
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1389
  {
1390
    TRACE_DISPATCH (this);
1391
    switch (lookup_type) {
1392 1393 1394 1395 1396 1397 1398 1399 1400
    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 已提交
1401
    default:			return TRACE_RETURN (c->default_return_value ());
1402
    }
1403 1404
  }

B
Behdad Esfahbod 已提交
1405
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
B
Behdad Esfahbod 已提交
1406
    TRACE_SANITIZE (this);
1407
    if (!u.header.sub_format.sanitize (c))
1408
      return TRACE_RETURN (false);
1409
    switch (lookup_type) {
1410 1411 1412 1413 1414 1415
    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));
1416
    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1417 1418 1419
    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 已提交
1420 1421 1422
    }
  }

1423
  protected:
B
Behdad Esfahbod 已提交
1424
  union {
B
Behdad Esfahbod 已提交
1425
  struct {
1426
    USHORT		sub_format;
B
Behdad Esfahbod 已提交
1427
  } header;
B
Behdad Esfahbod 已提交
1428 1429 1430 1431 1432 1433
  SinglePos		single;
  PairPos		pair;
  CursivePos		cursive;
  MarkBasePos		markBase;
  MarkLigPos		markLig;
  MarkMarkPos		markMark;
1434
  ContextPos		context;
B
Behdad Esfahbod 已提交
1435 1436
  ChainContextPos	chainContext;
  ExtensionPos		extension;
B
Behdad Esfahbod 已提交
1437
  } u;
B
Behdad Esfahbod 已提交
1438
  public:
B
Behdad Esfahbod 已提交
1439
  DEFINE_SIZE_UNION (2, header.sub_format);
B
Behdad Esfahbod 已提交
1440 1441 1442
};


B
Behdad Esfahbod 已提交
1443 1444
struct PosLookup : Lookup
{
1445 1446
  inline const PosLookupSubTable& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
B
Behdad Esfahbod 已提交
1447

B
Behdad Esfahbod 已提交
1448 1449 1450 1451 1452
  inline bool is_reverse (void) const
  {
    return false;
  }

B
Behdad Esfahbod 已提交
1453
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1454 1455
  {
    TRACE_COLLECT_GLYPHS (this);
1456
    c->set_recurse_func (NULL);
1457
    return TRACE_RETURN (dispatch (c));
1458 1459
  }

B
Behdad Esfahbod 已提交
1460 1461 1462
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1463
    hb_get_coverage_context_t c;
B
Behdad Esfahbod 已提交
1464 1465 1466
    const Coverage *last = NULL;
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
1467
      const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
1468 1469 1470
      if (coverage != last) {
        coverage->add_coverage (glyphs);
        last = coverage;
B
Behdad Esfahbod 已提交
1471 1472 1473 1474
      }
    }
  }

1475
  inline bool apply_once (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1476
  {
B
Behdad Esfahbod 已提交
1477
    TRACE_APPLY (this);
1478
    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
B
Behdad Esfahbod 已提交
1479
      return TRACE_RETURN (false);
1480
    return TRACE_RETURN (dispatch (c));
B
Behdad Esfahbod 已提交
1481 1482
  }

1483 1484
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);

B
Behdad Esfahbod 已提交
1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501
  template <typename context_t>
  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);

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

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
1536 1537 1538 1539

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

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

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

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

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

static void
1557
fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
B
Behdad Esfahbod 已提交
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
{
  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))
1568
    for (unsigned int k = j; k < i; k++) {
B
Behdad Esfahbod 已提交
1569 1570 1571 1572
      pos[i].x_offset -= pos[k].x_advance;
      pos[i].y_offset -= pos[k].y_advance;
    }
  else
1573
    for (unsigned int k = j + 1; k < i + 1; k++) {
B
Behdad Esfahbod 已提交
1574 1575 1576 1577 1578
      pos[i].x_offset += pos[k].x_advance;
      pos[i].y_offset += pos[k].y_advance;
    }
}

B
Behdad Esfahbod 已提交
1579
void
1580
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1581 1582
{
  buffer->clear_positions ();
1583 1584 1585 1586

  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 已提交
1587 1588
}

B
Behdad Esfahbod 已提交
1589
void
1590
GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1591
{
1592 1593
  unsigned int len;
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
B
Behdad Esfahbod 已提交
1594 1595
  hb_direction_t direction = buffer->props.direction;

B
Behdad Esfahbod 已提交
1596 1597 1598
  /* Handle cursive connections */
  for (unsigned int i = 0; i < len; i++)
    fix_cursive_minor_offset (pos, i, direction);
B
Behdad Esfahbod 已提交
1599 1600

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

B
Behdad Esfahbod 已提交
1604
  _hb_buffer_deallocate_gsubgpos_vars (buffer);
B
Behdad Esfahbod 已提交
1605 1606
}

B
Behdad Esfahbod 已提交
1607 1608 1609

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

1610
template <typename context_t>
1611
/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1612 1613 1614
{
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
  const PosLookup &l = gpos.get_lookup (lookup_index);
1615
  return l.dispatch (c);
1616 1617
}

1618
/*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1619
{
1620
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
B
Behdad Esfahbod 已提交
1621
  const PosLookup &l = gpos.get_lookup (lookup_index);
1622
  unsigned int saved_lookup_props = c->lookup_props;
1623
  c->set_lookup (l);
1624 1625 1626
  bool ret = l.apply_once (c);
  c->lookup_props = saved_lookup_props;
  return ret;
B
Behdad Esfahbod 已提交
1627 1628 1629
}


B
Behdad Esfahbod 已提交
1630 1631 1632 1633
#undef attach_lookback
#undef cursive_chain


B
Behdad Esfahbod 已提交
1634
} /* namespace OT */
1635

B
Behdad Esfahbod 已提交
1636

1637
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */