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

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

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

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

B
Behdad Esfahbod 已提交
37

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


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

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

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

B
Behdad Esfahbod 已提交
49 50
struct ValueFormat : USHORT
{
B
Behdad Esfahbod 已提交
51
  enum Flags {
52 53 54 55 56 57 58 59 60 61
    xPlacement	= 0x0001u,	/* Includes horizontal adjustment for placement */
    yPlacement	= 0x0002u,	/* Includes vertical adjustment for placement */
    xAdvance	= 0x0004u,	/* Includes horizontal adjustment for advance */
    yAdvance	= 0x0008u,	/* Includes vertical adjustment for advance */
    xPlaDevice	= 0x0010u,	/* Includes horizontal Device table for placement */
    yPlaDevice	= 0x0020u,	/* Includes vertical Device table for placement */
    xAdvDevice	= 0x0040u,	/* Includes horizontal Device table for advance */
    yAdvDevice	= 0x0080u,	/* Includes vertical Device table for advance */
    ignored	= 0x0F00u,	/* Was used in TrueType Open for MM fonts */
    reserved	= 0xF000u,	/* For future use */
62

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

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

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

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

    if (!format) return;

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

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

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

    if (!x_ppem && !y_ppem) return;

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

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

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

B
Behdad Esfahbod 已提交
158 159 160 161
    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
B
WIP  
Behdad Esfahbod 已提交
162 163 164 165

    return true;
  }

B
Behdad Esfahbod 已提交
166 167 168 169 170 171 172 173
  static inline OffsetTo<Device>& get_device (Value* value)
  { return *CastP<OffsetTo<Device> > (value); }
  static inline const OffsetTo<Device>& get_device (const Value* value)
  { return *CastP<OffsetTo<Device> > (value); }

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

B
WIP  
Behdad Esfahbod 已提交
174 175
  public:

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

268
  protected:
B
Behdad Esfahbod 已提交
269 270 271 272
  USHORT	format;			/* Format identifier--format = 2 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
  USHORT	anchorPoint;		/* Index to glyph contour point */
273 274
  public:
  DEFINE_SIZE_STATIC (8);
B
Behdad Esfahbod 已提交
275 276
};

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

285 286 287 288
      if (font->x_ppem)
	*x += (this+xDeviceTable).get_x_delta (font);
      if (font->y_ppem)
	*y += (this+yDeviceTable).get_x_delta (font);
B
Behdad Esfahbod 已提交
289 290
  }

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

297
  protected:
B
Behdad Esfahbod 已提交
298 299 300 301 302 303 304 305 306 307 308
  USHORT	format;			/* Format identifier--format = 3 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
  OffsetTo<Device>
		xDeviceTable;		/* Offset to Device table for X
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
  OffsetTo<Device>
		yDeviceTable;		/* Offset to Device table for Y
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
309 310
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
311 312
};

B
Behdad Esfahbod 已提交
313 314
struct Anchor
{
315
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
316 317
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
318 319
    *x = *y = 0;
    switch (u.format) {
320 321 322 323
    case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
    case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
    case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
    default:						 return;
B
Behdad Esfahbod 已提交
324 325 326
    }
  }

B
Behdad Esfahbod 已提交
327 328
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
329
    TRACE_SANITIZE (this);
330
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
331
    switch (u.format) {
332 333 334 335
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    case 2: return TRACE_RETURN (u.format2.sanitize (c));
    case 3: return TRACE_RETURN (u.format3.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
336 337 338
    }
  }

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


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

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

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


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

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

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

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

    const Anchor& mark_anchor = this + record.markAnchor;
414 415 416 417 418
    bool found;
    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
    /* If this subtable doesn't have an anchor for this base and this class,
     * return false such that the subsequent subtables have a chance at it. */
    if (unlikely (!found)) return TRACE_RETURN (false);
419 420 421

    hb_position_t mark_x, mark_y, base_x, base_y;

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

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

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

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


/* Lookups */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

559
  protected:
B
Behdad Esfahbod 已提交
560 561
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
562 563
  SinglePosFormat1	format1;
  SinglePosFormat2	format2;
B
Behdad Esfahbod 已提交
564 565 566 567
  } u;
};


B
Behdad Esfahbod 已提交
568 569
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
570
  friend struct PairSet;
B
Behdad Esfahbod 已提交
571

572
  protected:
B
Behdad Esfahbod 已提交
573 574 575 576 577
  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 已提交
578
  public:
579
  DEFINE_SIZE_ARRAY (2, values);
B
Behdad Esfahbod 已提交
580 581
};

B
Behdad Esfahbod 已提交
582 583
struct PairSet
{
B
Behdad Esfahbod 已提交
584 585
  friend struct PairPosFormat1;

586 587 588 589 590 591 592 593
  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);

594
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
595 596 597
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
    {
B
Minor  
Behdad Esfahbod 已提交
598
      c->input->add (record->secondGlyph);
599 600 601 602
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }
  }

B
Behdad Esfahbod 已提交
603
  inline bool apply (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
604 605 606
		     const ValueFormat *valueFormats,
		     unsigned int pos) const
  {
B
Behdad Esfahbod 已提交
607
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
608
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
609 610 611 612
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);

613
    const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
614
    unsigned int count = len;
615 616 617 618 619 620 621

    /* Hand-coded bsearch. */
    if (unlikely (!count))
      return TRACE_RETURN (false);
    hb_codepoint_t x = buffer->info[pos].codepoint;
    int min = 0, max = (int) count - 1;
    while (min <= max)
B
Behdad Esfahbod 已提交
622
    {
623 624 625 626 627 628 629 630
      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 已提交
631
      {
632
	valueFormats[0].apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
633
				     &record->values[0], buffer->cur_pos());
634
	valueFormats[1].apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
635
				     &record->values[len1], buffer->pos[pos]);
B
Behdad Esfahbod 已提交
636 637
	if (len2)
	  pos++;
B
Behdad Esfahbod 已提交
638
	buffer->idx = pos;
639
	return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
640 641 642
      }
    }

643
    return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
644 645 646
  }

  struct sanitize_closure_t {
B
Behdad Esfahbod 已提交
647 648
    const void *base;
    const ValueFormat *valueFormats;
B
Behdad Esfahbod 已提交
649 650 651 652
    unsigned int len1; /* valueFormats[0].get_len() */
    unsigned int stride; /* 1 + len1 + len2 */
  };

B
Behdad Esfahbod 已提交
653 654
  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
  {
B
Behdad Esfahbod 已提交
655
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
656
    if (!(c->check_struct (this)
657
       && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
658 659

    unsigned int count = len;
B
Behdad Esfahbod 已提交
660
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
661 662
    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 已提交
663 664
  }

665
  protected:
B
Behdad Esfahbod 已提交
666
  USHORT	len;			/* Number of PairValueRecords */
667
  USHORT	arrayZ[VAR];		/* Array of PairValueRecords--ordered
B
Behdad Esfahbod 已提交
668
					 * by GlyphID of the second glyph */
B
Behdad Esfahbod 已提交
669
  public:
670
  DEFINE_SIZE_ARRAY (2, arrayZ);
B
Behdad Esfahbod 已提交
671
};
B
Behdad Esfahbod 已提交
672

B
Behdad Esfahbod 已提交
673 674
struct PairPosFormat1
{
675 676 677
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
678
    (this+coverage).add_coverage (c->input);
679 680 681 682 683
    unsigned int count = pairSet.len;
    for (unsigned int i = 0; i < count; i++)
      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
  }

684 685 686 687 688
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
689
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
690
  {
B
Behdad Esfahbod 已提交
691
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
692 693
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
694
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
695

696
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
697
    skippy_iter.reset (buffer->idx, 1);
698
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
699

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

B
Behdad Esfahbod 已提交
703 704
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
705
    TRACE_SANITIZE (this);
706 707 708

    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
B
Behdad Esfahbod 已提交
709 710 711 712 713 714
    PairSet::sanitize_closure_t closure = {
      this,
      &valueFormat1,
      len1,
      1 + len1 + len2
    };
715

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

719
  protected:
B
Behdad Esfahbod 已提交
720 721 722 723
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
724
  ValueFormat	valueFormat1;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
725 726
					 * ValueRecord1--for the first glyph
					 * in the pair--may be zero (0) */
727
  ValueFormat	valueFormat2;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
728 729 730 731 732
					 * ValueRecord2--for the second glyph
					 * in the pair--may be zero (0) */
  OffsetArrayOf<PairSet>
		pairSet;		/* Array of PairSet tables
					 * ordered by Coverage Index */
733
  public:
734
  DEFINE_SIZE_ARRAY (10, pairSet);
B
Behdad Esfahbod 已提交
735 736
};

B
Behdad Esfahbod 已提交
737 738
struct PairPosFormat2
{
739 740 741
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
742
    /* (this+coverage).add_coverage (c->input); // Don't need this. */
743 744 745 746

    unsigned int count1 = class1Count;
    const ClassDef &klass1 = this+classDef1;
    for (unsigned int i = 0; i < count1; i++)
B
Minor  
Behdad Esfahbod 已提交
747
      klass1.add_class (c->input, i);
748 749 750 751

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

755 756 757 758 759
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
760
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
761
  {
B
Behdad Esfahbod 已提交
762
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
763 764
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
765
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
766

767
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
768
    skippy_iter.reset (buffer->idx, 1);
769
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
770 771 772 773 774

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

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

B
Behdad Esfahbod 已提交
779
    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
780
    valueFormat1.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
781
			      v, buffer->cur_pos());
782
    valueFormat2.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
783
			      v + len1, buffer->pos[skippy_iter.idx]);
B
Behdad Esfahbod 已提交
784

B
Behdad Esfahbod 已提交
785
    buffer->idx = skippy_iter.idx;
B
Behdad Esfahbod 已提交
786
    if (len2)
B
Behdad Esfahbod 已提交
787
      buffer->idx++;
B
Behdad Esfahbod 已提交
788

789
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
790 791
  }

B
Behdad Esfahbod 已提交
792 793
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
794
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
795 796 797
    if (!(c->check_struct (this)
       && coverage.sanitize (c, this)
       && classDef1.sanitize (c, this)
798
       && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
799

800 801 802
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int stride = len1 + len2;
B
Behdad Esfahbod 已提交
803
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
804
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
805 806 807
    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 已提交
808
  }
B
Behdad Esfahbod 已提交
809

810
  protected:
B
Behdad Esfahbod 已提交
811 812 813 814
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
815
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
816 817
					 * first glyph of the pair--may be zero
					 * (0) */
818
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
					 * 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 已提交
836
  public:
837
  DEFINE_SIZE_ARRAY (16, values);
B
Behdad Esfahbod 已提交
838 839
};

B
Behdad Esfahbod 已提交
840 841
struct PairPos
{
842
  template <typename context_t>
843
  inline typename context_t::return_t dispatch (context_t *c) const
844
  {
845
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
846
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
847
    switch (u.format) {
848 849
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
B
Behdad Esfahbod 已提交
850
    default:return TRACE_RETURN (c->default_return_value ());
851 852 853
    }
  }

854
  protected:
B
Behdad Esfahbod 已提交
855 856
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
857 858
  PairPosFormat1	format1;
  PairPosFormat2	format2;
B
Behdad Esfahbod 已提交
859 860 861 862
  } u;
};


B
Behdad Esfahbod 已提交
863 864
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
865 866
  friend struct CursivePosFormat1;

B
Behdad Esfahbod 已提交
867 868
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
B
Behdad Esfahbod 已提交
869
    TRACE_SANITIZE (this);
870
    return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
871 872
  }

873
  protected:
B
Behdad Esfahbod 已提交
874 875 876 877 878 879 880 881
  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 已提交
882 883
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
884 885
};

B
Behdad Esfahbod 已提交
886 887
struct CursivePosFormat1
{
888 889 890
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
891
    (this+coverage).add_coverage (c->input);
892 893
  }

894 895 896 897 898
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
899
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
900
  {
B
Behdad Esfahbod 已提交
901
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
902
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
903 904

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

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

910
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
911
    skippy_iter.reset (buffer->idx, 1);
912
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
913

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

B
Behdad Esfahbod 已提交
917
    unsigned int i = buffer->idx;
B
Behdad Esfahbod 已提交
918
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
919

920
    hb_position_t entry_x, entry_y, exit_x, exit_y;
B
Behdad Esfahbod 已提交
921 922
    (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 已提交
923

B
Behdad Esfahbod 已提交
924
    hb_glyph_position_t *pos = buffer->pos;
B
Behdad Esfahbod 已提交
925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959

    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 已提交
960 961
    }

B
Behdad Esfahbod 已提交
962
    /* Cross-direction adjustment */
963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980

    /* 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 已提交
981 982
    }

983 984 985 986 987 988
    pos[child].cursive_chain() = parent - child;
    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
      pos[child].y_offset = y_offset;
    else
      pos[child].x_offset = x_offset;

B
Behdad Esfahbod 已提交
989
    buffer->idx = j;
990
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
991 992
  }

B
Behdad Esfahbod 已提交
993 994
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
995
    TRACE_SANITIZE (this);
996
    return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
B
Behdad Esfahbod 已提交
997 998
  }

999
  protected:
B
Behdad Esfahbod 已提交
1000 1001 1002 1003 1004 1005 1006
  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 */
1007
  public:
1008
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
B
Behdad Esfahbod 已提交
1009 1010
};

B
Behdad Esfahbod 已提交
1011 1012
struct CursivePos
{
1013
  template <typename context_t>
1014
  inline typename context_t::return_t dispatch (context_t *c) const
1015
  {
1016
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
1017
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1018
    switch (u.format) {
1019
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1020
    default:return TRACE_RETURN (c->default_return_value ());
1021 1022 1023
    }
  }

1024
  protected:
B
Behdad Esfahbod 已提交
1025 1026
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1027
  CursivePosFormat1	format1;
B
Behdad Esfahbod 已提交
1028 1029 1030 1031
  } u;
};


1032 1033 1034
typedef AnchorMatrix BaseArray;		/* base-major--
					 * in order of BaseCoverage Index--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1035
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1036

B
Behdad Esfahbod 已提交
1037 1038
struct MarkBasePosFormat1
{
1039 1040 1041
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1042 1043
    (this+markCoverage).add_coverage (c->input);
    (this+baseCoverage).add_coverage (c->input);
1044 1045
  }

1046 1047 1048 1049 1050
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1051
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1052
  {
B
Behdad Esfahbod 已提交
1053
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1054 1055
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1056
    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1057 1058

    /* now we search backwards for a non-mark glyph */
1059
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1060
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
1061
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1062
    do {
B
Behdad Esfahbod 已提交
1063
      if (!skippy_iter.prev ()) return TRACE_RETURN (false);
1064
      /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
B
Behdad Esfahbod 已提交
1065
      if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
1066 1067
      skippy_iter.reject ();
    } while (1);
1068

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

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

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

B
Behdad Esfahbod 已提交
1078 1079
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1080
    TRACE_SANITIZE (this);
1081 1082
    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 已提交
1083 1084
  }

1085
  protected:
B
Behdad Esfahbod 已提交
1086
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1087 1088
  OffsetTo<Coverage>
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
1089
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1090 1091
  OffsetTo<Coverage>
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
1092 1093
					 * beginning of MarkBasePos subtable */
  USHORT	classCount;		/* Number of classes defined for marks */
B
Behdad Esfahbod 已提交
1094 1095
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1096
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1097 1098
  OffsetTo<BaseArray>
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
1099
					 * beginning of MarkBasePos subtable */
1100 1101
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1102 1103
};

B
Behdad Esfahbod 已提交
1104 1105
struct MarkBasePos
{
1106
  template <typename context_t>
1107
  inline typename context_t::return_t dispatch (context_t *c) const
1108
  {
1109
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
1110
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1111
    switch (u.format) {
1112
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1113
    default:return TRACE_RETURN (c->default_return_value ());
1114 1115 1116
    }
  }

1117
  protected:
B
Behdad Esfahbod 已提交
1118 1119
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1120
  MarkBasePosFormat1	format1;
B
Behdad Esfahbod 已提交
1121 1122 1123 1124
  } u;
};


1125 1126 1127
typedef AnchorMatrix LigatureAttach;	/* component-major--
					 * in order of writing direction--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1128
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1129

1130
typedef OffsetListOf<LigatureAttach> LigatureArray;
B
Behdad Esfahbod 已提交
1131
					/* Array of LigatureAttach
B
Behdad Esfahbod 已提交
1132 1133 1134
					 * tables ordered by
					 * LigatureCoverage Index */

B
Behdad Esfahbod 已提交
1135 1136
struct MarkLigPosFormat1
{
1137 1138 1139
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1140 1141
    (this+markCoverage).add_coverage (c->input);
    (this+ligatureCoverage).add_coverage (c->input);
1142 1143
  }

1144 1145 1146 1147 1148
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1149
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1150
  {
B
Behdad Esfahbod 已提交
1151
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1152 1153
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1154
    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1155 1156

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

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

B
Behdad Esfahbod 已提交
1165
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
1166
    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
1167
    if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1168 1169

    const LigatureArray& lig_array = this+ligatureArray;
1170
    const LigatureAttach& lig_attach = lig_array[lig_index];
1171 1172

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

B
Behdad Esfahbod 已提交
1176 1177 1178 1179
    /* 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 已提交
1180
    unsigned int comp_index;
B
Behdad Esfahbod 已提交
1181 1182 1183
    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 已提交
1184
    if (lig_id && lig_id == mark_id && mark_comp > 0)
B
Behdad Esfahbod 已提交
1185
      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
B
Behdad Esfahbod 已提交
1186
    else
B
Behdad Esfahbod 已提交
1187
      comp_index = comp_count - 1;
B
Behdad Esfahbod 已提交
1188

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

B
Behdad Esfahbod 已提交
1192 1193
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1194
    TRACE_SANITIZE (this);
1195 1196
    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 已提交
1197 1198
  }

1199
  protected:
B
Behdad Esfahbod 已提交
1200
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1201 1202
  OffsetTo<Coverage>
		markCoverage;		/* Offset to Mark Coverage table--from
B
Behdad Esfahbod 已提交
1203
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1204 1205
  OffsetTo<Coverage>
		ligatureCoverage;	/* Offset to Ligature Coverage
B
Behdad Esfahbod 已提交
1206 1207 1208
					 * table--from beginning of MarkLigPos
					 * subtable */
  USHORT	classCount;		/* Number of defined mark classes */
B
Behdad Esfahbod 已提交
1209 1210
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1211
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1212 1213
  OffsetTo<LigatureArray>
		ligatureArray;		/* Offset to LigatureArray table--from
B
Behdad Esfahbod 已提交
1214
					 * beginning of MarkLigPos subtable */
1215 1216
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1217 1218
};

B
Behdad Esfahbod 已提交
1219 1220
struct MarkLigPos
{
1221
  template <typename context_t>
1222
  inline typename context_t::return_t dispatch (context_t *c) const
1223
  {
1224
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
1225
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1226
    switch (u.format) {
1227
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1228
    default:return TRACE_RETURN (c->default_return_value ());
1229 1230 1231
    }
  }

1232
  protected:
B
Behdad Esfahbod 已提交
1233 1234
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1235
  MarkLigPosFormat1	format1;
B
Behdad Esfahbod 已提交
1236 1237 1238 1239
  } u;
};


1240 1241 1242 1243
typedef AnchorMatrix Mark2Array;	/* mark2-major--
					 * in order of Mark2Coverage Index--,
					 * mark1-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1244

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

1254 1255 1256 1257 1258
  inline const Coverage &get_coverage (void) const
  {
    return this+mark1Coverage;
  }

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

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

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

B
Behdad Esfahbod 已提交
1274 1275
    unsigned int j = skippy_iter.idx;

B
Behdad Esfahbod 已提交
1276 1277 1278 1279
    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]);
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294

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

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

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

B
Behdad Esfahbod 已提交
1303 1304
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1305
    TRACE_SANITIZE (this);
1306 1307 1308
    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 已提交
1309 1310
  }

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

B
Behdad Esfahbod 已提交
1332 1333
struct MarkMarkPos
{
1334
  template <typename context_t>
1335
  inline typename context_t::return_t dispatch (context_t *c) const
1336
  {
1337
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
1338
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
1339
    switch (u.format) {
1340
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1341
    default:return TRACE_RETURN (c->default_return_value ());
1342 1343 1344
    }
  }

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


B
Minor  
Behdad Esfahbod 已提交
1353
struct ContextPos : Context {};
B
Behdad Esfahbod 已提交
1354

B
Minor  
Behdad Esfahbod 已提交
1355
struct ChainContextPos : ChainContext {};
B
Behdad Esfahbod 已提交
1356

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


1363

B
Behdad Esfahbod 已提交
1364 1365 1366 1367 1368
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
1369 1370
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
1371 1372
  friend struct PosLookup;

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

1385
  template <typename context_t>
1386
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1387
  {
1388
    TRACE_DISPATCH (this, lookup_type);
1389
    /* The sub_format passed to may_dispatch is unnecessary but harmless. */
B
Behdad Esfahbod 已提交
1390
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
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
  }

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


B
Behdad Esfahbod 已提交
1423 1424
struct PosLookup : Lookup
{
1425
  inline const PosLookupSubTable& get_subtable (unsigned int i) const
1426
  { return Lookup::get_subtable<PosLookupSubTable> (i); }
B
Behdad Esfahbod 已提交
1427

B
Behdad Esfahbod 已提交
1428 1429 1430 1431 1432
  inline bool is_reverse (void) const
  {
    return false;
  }

B
Behdad Esfahbod 已提交
1433 1434 1435 1436 1437 1438
  inline bool apply (hb_apply_context_t *c) const
  {
    TRACE_APPLY (this);
    return TRACE_RETURN (dispatch (c));
  }

B
Behdad Esfahbod 已提交
1439
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1440 1441
  {
    TRACE_COLLECT_GLYPHS (this);
1442
    return TRACE_RETURN (dispatch (c));
1443 1444
  }

B
Behdad Esfahbod 已提交
1445 1446 1447
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1448 1449
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1450 1451
  }

1452 1453
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);

B
Behdad Esfahbod 已提交
1454 1455 1456 1457 1458
  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
1459
  { return Lookup::dispatch<PosLookupSubTable> (c); }
B
Behdad Esfahbod 已提交
1460

B
Behdad Esfahbod 已提交
1461 1462
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1463
    TRACE_SANITIZE (this);
1464
    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1465
    return TRACE_RETURN (dispatch (c));
B
Behdad Esfahbod 已提交
1466
  }
B
Behdad Esfahbod 已提交
1467 1468
};

B
Behdad Esfahbod 已提交
1469
typedef OffsetListOf<PosLookup> PosLookupList;
B
Behdad Esfahbod 已提交
1470 1471

/*
B
Behdad Esfahbod 已提交
1472
 * GPOS -- The Glyph Positioning Table
B
Behdad Esfahbod 已提交
1473 1474
 */

B
Behdad Esfahbod 已提交
1475 1476
struct GPOS : GSUBGPOS
{
1477
  static const hb_tag_t tableTag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1478

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

1482
  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1483
  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
B
Behdad Esfahbod 已提交
1484

B
Behdad Esfahbod 已提交
1485 1486
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1487
    TRACE_SANITIZE (this);
1488
    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1489
    const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1490
    return TRACE_RETURN (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1491
  }
1492 1493
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
1494 1495
};

B
Behdad Esfahbod 已提交
1496 1497 1498 1499

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

B
Behdad Esfahbod 已提交
1504
  j += i;
B
Behdad Esfahbod 已提交
1505

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

B
Behdad Esfahbod 已提交
1508
  fix_cursive_minor_offset (pos, j, direction);
B
Behdad Esfahbod 已提交
1509

B
Behdad Esfahbod 已提交
1510 1511 1512 1513
  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 已提交
1514 1515 1516
}

static void
1517
fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
B
Behdad Esfahbod 已提交
1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
{
  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))
1528
    for (unsigned int k = j; k < i; k++) {
B
Behdad Esfahbod 已提交
1529 1530 1531 1532
      pos[i].x_offset -= pos[k].x_advance;
      pos[i].y_offset -= pos[k].y_advance;
    }
  else
1533
    for (unsigned int k = j + 1; k < i + 1; k++) {
B
Behdad Esfahbod 已提交
1534 1535 1536 1537 1538
      pos[i].x_offset += pos[k].x_advance;
      pos[i].y_offset += pos[k].y_advance;
    }
}

B
Behdad Esfahbod 已提交
1539
void
1540
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1541 1542
{
  buffer->clear_positions ();
1543 1544 1545 1546

  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 已提交
1547 1548
}

B
Behdad Esfahbod 已提交
1549
void
1550
GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1551
{
1552 1553
  _hb_buffer_assert_gsubgpos_vars (buffer);

1554 1555
  unsigned int len;
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
B
Behdad Esfahbod 已提交
1556 1557
  hb_direction_t direction = buffer->props.direction;

B
Behdad Esfahbod 已提交
1558 1559 1560
  /* Handle cursive connections */
  for (unsigned int i = 0; i < len; i++)
    fix_cursive_minor_offset (pos, i, direction);
B
Behdad Esfahbod 已提交
1561 1562

  /* Handle attachments */
B
Behdad Esfahbod 已提交
1563
  for (unsigned int i = 0; i < len; i++)
1564
    fix_mark_attachment (pos, i, direction);
B
Behdad Esfahbod 已提交
1565 1566
}

B
Behdad Esfahbod 已提交
1567 1568 1569

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

1570
template <typename context_t>
1571
/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1572 1573 1574
{
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
  const PosLookup &l = gpos.get_lookup (lookup_index);
1575
  return l.dispatch (c);
1576 1577
}

1578
/*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1579
{
1580
  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
B
Behdad Esfahbod 已提交
1581
  const PosLookup &l = gpos.get_lookup (lookup_index);
1582
  unsigned int saved_lookup_props = c->lookup_props;
1583 1584 1585
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1586
  bool ret = l.dispatch (c);
1587
  c->set_lookup_index (saved_lookup_index);
1588
  c->set_lookup_props (saved_lookup_props);
1589
  return ret;
B
Behdad Esfahbod 已提交
1590 1591 1592
}


B
Behdad Esfahbod 已提交
1593 1594 1595 1596
#undef attach_lookback
#undef cursive_chain


B
Behdad Esfahbod 已提交
1597
} /* namespace OT */
1598

B
Behdad Esfahbod 已提交
1599

1600
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */