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

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

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

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

B
Behdad Esfahbod 已提交
37

38
/* buffer **position** var allocations */
39 40 41 42 43 44 45 46 47 48 49
#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
#define attach_type() var.u8[2] /* attachment type */
/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */

enum attach_type_t {
  ATTACH_TYPE_NONE	= 0X00,

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


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

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

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

B
Behdad Esfahbod 已提交
58 59
struct ValueFormat : USHORT
{
B
Behdad Esfahbod 已提交
60
  enum Flags {
61 62 63 64 65 66 67 68 69 70
    xPlacement	= 0x0001u,	/* Includes horizontal adjustment for placement */
    yPlacement	= 0x0002u,	/* Includes vertical adjustment for placement */
    xAdvance	= 0x0004u,	/* Includes horizontal adjustment for advance */
    yAdvance	= 0x0008u,	/* Includes vertical adjustment for advance */
    xPlaDevice	= 0x0010u,	/* Includes horizontal Device table for placement */
    yPlaDevice	= 0x0020u,	/* Includes vertical Device table for placement */
    xAdvDevice	= 0x0040u,	/* Includes horizontal Device table for advance */
    yAdvDevice	= 0x0080u,	/* Includes vertical Device table for advance */
    ignored	= 0x0F00u,	/* Was used in TrueType Open for MM fonts */
    reserved	= 0xF000u,	/* For future use */
71

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

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

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

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

    if (!format) return;

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

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

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

    if (!x_ppem && !y_ppem) return;

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

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

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

B
Behdad Esfahbod 已提交
167 168 169 170
    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
B
WIP  
Behdad Esfahbod 已提交
171 172 173 174

    return true;
  }

B
Behdad Esfahbod 已提交
175 176 177 178 179 180 181 182
  static inline OffsetTo<Device>& get_device (Value* value)
  { return *CastP<OffsetTo<Device> > (value); }
  static inline const OffsetTo<Device>& get_device (const Value* value)
  { return *CastP<OffsetTo<Device> > (value); }

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

B
WIP  
Behdad Esfahbod 已提交
183 184
  public:

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

K
Konstantin Ritt 已提交
265 266 267 268
      ret = (x_ppem || y_ppem) &&
             font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
      *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
      *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
B
Behdad Esfahbod 已提交
269 270
  }

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

277
  protected:
B
Behdad Esfahbod 已提交
278 279 280 281
  USHORT	format;			/* Format identifier--format = 2 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
  USHORT	anchorPoint;		/* Index to glyph contour point */
282 283
  public:
  DEFINE_SIZE_STATIC (8);
B
Behdad Esfahbod 已提交
284 285
};

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

294 295 296 297
      if (font->x_ppem)
	*x += (this+xDeviceTable).get_x_delta (font);
      if (font->y_ppem)
	*y += (this+yDeviceTable).get_x_delta (font);
B
Behdad Esfahbod 已提交
298 299
  }

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

306
  protected:
B
Behdad Esfahbod 已提交
307 308 309 310 311 312 313 314 315 316 317
  USHORT	format;			/* Format identifier--format = 3 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
  OffsetTo<Device>
		xDeviceTable;		/* Offset to Device table for X
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
  OffsetTo<Device>
		yDeviceTable;		/* Offset to Device table for Y
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
318 319
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
320 321
};

B
Behdad Esfahbod 已提交
322 323
struct Anchor
{
324
  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
325 326
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
327 328
    *x = *y = 0;
    switch (u.format) {
329 330 331 332
    case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
    case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
    case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
    default:						 return;
B
Behdad Esfahbod 已提交
333 334 335
    }
  }

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

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


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

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

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


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

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

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

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

    const Anchor& mark_anchor = this + record.markAnchor;
423 424 425 426
    bool found;
    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
    /* If this subtable doesn't have an anchor for this base and this class,
     * return false such that the subsequent subtables have a chance at it. */
B
Behdad Esfahbod 已提交
427
    if (unlikely (!found)) return_trace (false);
428 429 430

    hb_position_t mark_x, mark_y, base_x, base_y;

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

B
Behdad Esfahbod 已提交
434
    hb_glyph_position_t &o = buffer->cur_pos();
B
Behdad Esfahbod 已提交
435 436
    o.x_offset = base_x - mark_x;
    o.y_offset = base_y - mark_y;
437
    o.attach_type() = ATTACH_TYPE_MARK;
438
    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
439
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
440

B
Behdad Esfahbod 已提交
441
    buffer->idx++;
B
Behdad Esfahbod 已提交
442
    return_trace (true);
443
  }
B
Behdad Esfahbod 已提交
444

B
Behdad Esfahbod 已提交
445 446
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
447
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
448
    return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
B
Behdad Esfahbod 已提交
449
  }
B
Behdad Esfahbod 已提交
450 451 452 453 454
};


/* Lookups */

B
Behdad Esfahbod 已提交
455 456
struct SinglePosFormat1
{
457 458 459
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
460
    (this+coverage).add_coverage (c->input);
461 462
  }

463 464 465 466 467
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
468
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
469
  {
B
Behdad Esfahbod 已提交
470
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
471 472
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
473
    if (likely (index == NOT_COVERED)) return_trace (false);
474

475
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
476
			     values, buffer->cur_pos());
477

B
Behdad Esfahbod 已提交
478
    buffer->idx++;
B
Behdad Esfahbod 已提交
479
    return_trace (true);
B
Behdad Esfahbod 已提交
480 481
  }

B
Behdad Esfahbod 已提交
482 483
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
484
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
485 486 487
    return_trace (c->check_struct (this) &&
		  coverage.sanitize (c, this) &&
		  valueFormat.sanitize_value (c, this, values));
B
Behdad Esfahbod 已提交
488 489
  }

490
  protected:
B
Behdad Esfahbod 已提交
491 492 493 494
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
495
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
496 497 498 499
					 * ValueRecord */
  ValueRecord	values;			/* Defines positioning
					 * value(s)--applied to all glyphs in
					 * the Coverage table */
B
Behdad Esfahbod 已提交
500
  public:
501
  DEFINE_SIZE_ARRAY (6, values);
B
Behdad Esfahbod 已提交
502 503
};

B
Behdad Esfahbod 已提交
504 505
struct SinglePosFormat2
{
506 507 508
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
509
    (this+coverage).add_coverage (c->input);
510 511
  }

512 513 514 515 516
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
517
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
518
  {
B
Behdad Esfahbod 已提交
519
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
520 521
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
522
    if (likely (index == NOT_COVERED)) return_trace (false);
523

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

526
    valueFormat.apply_value (c->font, c->direction, this,
B
Behdad Esfahbod 已提交
527
			     &values[index * valueFormat.get_len ()],
B
Behdad Esfahbod 已提交
528
			     buffer->cur_pos());
529

B
Behdad Esfahbod 已提交
530
    buffer->idx++;
B
Behdad Esfahbod 已提交
531
    return_trace (true);
B
Behdad Esfahbod 已提交
532 533
  }

B
Behdad Esfahbod 已提交
534 535
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
536
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
537 538 539
    return_trace (c->check_struct (this) &&
		  coverage.sanitize (c, this) &&
		  valueFormat.sanitize_values (c, this, values, valueCount));
B
Behdad Esfahbod 已提交
540 541
  }

542
  protected:
B
Behdad Esfahbod 已提交
543 544 545 546
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
547
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
548 549 550 551
					 * ValueRecord */
  USHORT	valueCount;		/* Number of ValueRecords */
  ValueRecord	values;			/* Array of ValueRecords--positioning
					 * values applied to glyphs */
B
Behdad Esfahbod 已提交
552
  public:
553
  DEFINE_SIZE_ARRAY (8, values);
B
Behdad Esfahbod 已提交
554 555
};

B
Behdad Esfahbod 已提交
556 557
struct SinglePos
{
558
  template <typename context_t>
559
  inline typename context_t::return_t dispatch (context_t *c) const
560
  {
561
    TRACE_DISPATCH (this, u.format);
562
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
563
    switch (u.format) {
B
Behdad Esfahbod 已提交
564 565 566
    case 1: return_trace (c->dispatch (u.format1));
    case 2: return_trace (c->dispatch (u.format2));
    default:return_trace (c->default_return_value ());
567 568 569
    }
  }

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


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

583
  protected:
B
Behdad Esfahbod 已提交
584 585 586 587 588
  GlyphID	secondGlyph;		/* GlyphID of second glyph in the
					 * pair--first glyph is listed in the
					 * Coverage table */
  ValueRecord	values;			/* Positioning data for the first glyph
					 * followed by for second glyph */
B
Behdad Esfahbod 已提交
589
  public:
590
  DEFINE_SIZE_ARRAY (2, values);
B
Behdad Esfahbod 已提交
591 592
};

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

597 598 599 600 601 602 603 604
  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
			      const ValueFormat *valueFormats) const
  {
    TRACE_COLLECT_GLYPHS (this);
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);

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

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

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

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

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

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

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

    unsigned int count = len;
B
Behdad Esfahbod 已提交
671
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
B
Behdad Esfahbod 已提交
672 673
    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
		  closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
B
Behdad Esfahbod 已提交
674 675
  }

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

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

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

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

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

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

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

718 719
    if (!c->check_struct (this)) return_trace (false);

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

729
    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
B
Behdad Esfahbod 已提交
730 731
  }

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

B
Behdad Esfahbod 已提交
750 751
struct PairPosFormat2
{
752 753 754
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
755
    (this+coverage).add_coverage (c->input);
756 757 758 759

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

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

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
802
    return_trace (true);
B
Behdad Esfahbod 已提交
803 804
  }

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

813 814 815
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int stride = len1 + len2;
B
Behdad Esfahbod 已提交
816
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
817
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
B
Behdad Esfahbod 已提交
818 819 820
    return_trace (c->check_array (values, record_size, count) &&
		  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
		  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
B
Behdad Esfahbod 已提交
821
  }
B
Behdad Esfahbod 已提交
822

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

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

867
  protected:
B
Behdad Esfahbod 已提交
868 869
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
870 871
  PairPosFormat1	format1;
  PairPosFormat2	format2;
B
Behdad Esfahbod 已提交
872 873 874 875
  } u;
};


B
Behdad Esfahbod 已提交
876 877
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
878 879
  friend struct CursivePosFormat1;

B
Behdad Esfahbod 已提交
880 881
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
  {
B
Behdad Esfahbod 已提交
882
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
883
    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
884 885
  }

886
  protected:
B
Behdad Esfahbod 已提交
887 888 889 890 891 892 893 894
  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 已提交
895 896
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
897 898
};

899 900 901
static void
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);

B
Behdad Esfahbod 已提交
902 903
struct CursivePosFormat1
{
904 905 906
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
907
    (this+coverage).add_coverage (c->input);
908 909
  }

910 911 912 913 914
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

B
Behdad Esfahbod 已提交
915
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
916
  {
B
Behdad Esfahbod 已提交
917
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
918
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
919 920

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

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

926
    hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
927
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
928
    if (!skippy_iter.next ()) return_trace (false);
929

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

B
Behdad Esfahbod 已提交
933
    unsigned int i = buffer->idx;
B
Behdad Esfahbod 已提交
934
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
935

936
    hb_position_t entry_x, entry_y, exit_x, exit_y;
B
Behdad Esfahbod 已提交
937 938
    (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 已提交
939

B
Behdad Esfahbod 已提交
940
    hb_glyph_position_t *pos = buffer->pos;
B
Behdad Esfahbod 已提交
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975

    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 已提交
976 977
    }

B
Behdad Esfahbod 已提交
978
    /* Cross-direction adjustment */
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996

    /* 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 已提交
997 998
    }

999 1000 1001 1002 1003 1004 1005
    /* If child was already connected to someone else, walk through its old
     * chain and reverse the link direction, such that the whole tree of its
     * previous connection now attaches to new parent.  Watch out for case
     * where new parent is on the path from old chain...
     */
    reverse_cursive_minor_offset (pos, child, c->direction, parent);

1006 1007
    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
    pos[child].attach_chain() = (int) parent - (int) child;
1008
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE;
1009 1010 1011 1012 1013
    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
      pos[child].y_offset = y_offset;
    else
      pos[child].x_offset = x_offset;

B
Behdad Esfahbod 已提交
1014
    buffer->idx = j;
B
Behdad Esfahbod 已提交
1015
    return_trace (true);
B
Behdad Esfahbod 已提交
1016 1017
  }

B
Behdad Esfahbod 已提交
1018 1019
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1020
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1021
    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
B
Behdad Esfahbod 已提交
1022 1023
  }

1024
  protected:
B
Behdad Esfahbod 已提交
1025 1026 1027 1028 1029 1030 1031
  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 */
1032
  public:
1033
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
B
Behdad Esfahbod 已提交
1034 1035
};

B
Behdad Esfahbod 已提交
1036 1037
struct CursivePos
{
1038
  template <typename context_t>
1039
  inline typename context_t::return_t dispatch (context_t *c) const
1040
  {
1041
    TRACE_DISPATCH (this, u.format);
1042
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1043
    switch (u.format) {
B
Behdad Esfahbod 已提交
1044 1045
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1046 1047 1048
    }
  }

1049
  protected:
B
Behdad Esfahbod 已提交
1050 1051
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1052
  CursivePosFormat1	format1;
B
Behdad Esfahbod 已提交
1053 1054 1055 1056
  } u;
};


1057 1058 1059
typedef AnchorMatrix BaseArray;		/* base-major--
					 * in order of BaseCoverage Index--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1060
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1061

B
Behdad Esfahbod 已提交
1062 1063
struct MarkBasePosFormat1
{
1064 1065 1066
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1067 1068
    (this+markCoverage).add_coverage (c->input);
    (this+baseCoverage).add_coverage (c->input);
1069 1070
  }

1071 1072 1073 1074 1075
  inline const Coverage &get_coverage (void) const
  {
    return this+markCoverage;
  }

B
Behdad Esfahbod 已提交
1076
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1077
  {
B
Behdad Esfahbod 已提交
1078
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1079 1080
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1081
    if (likely (mark_index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
1082 1083

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

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

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

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

B
Behdad Esfahbod 已提交
1103 1104
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1105
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1106 1107 1108 1109 1110
    return_trace (c->check_struct (this) &&
		  markCoverage.sanitize (c, this) &&
		  baseCoverage.sanitize (c, this) &&
		  markArray.sanitize (c, this) &&
		  baseArray.sanitize (c, this, (unsigned int) classCount));
B
Behdad Esfahbod 已提交
1111 1112
  }

1113
  protected:
B
Behdad Esfahbod 已提交
1114
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1115 1116
  OffsetTo<Coverage>
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
1117
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1118 1119
  OffsetTo<Coverage>
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
1120 1121
					 * beginning of MarkBasePos subtable */
  USHORT	classCount;		/* Number of classes defined for marks */
B
Behdad Esfahbod 已提交
1122 1123
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1124
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1125 1126
  OffsetTo<BaseArray>
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
1127
					 * beginning of MarkBasePos subtable */
1128 1129
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1130 1131
};

B
Behdad Esfahbod 已提交
1132 1133
struct MarkBasePos
{
1134
  template <typename context_t>
1135
  inline typename context_t::return_t dispatch (context_t *c) const
1136
  {
1137
    TRACE_DISPATCH (this, u.format);
1138
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1139
    switch (u.format) {
B
Behdad Esfahbod 已提交
1140 1141
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1142 1143 1144
    }
  }

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


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

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

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

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

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

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

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

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

    const LigatureArray& lig_array = this+ligatureArray;
1198
    const LigatureAttach& lig_attach = lig_array[lig_index];
1199 1200

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

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

B
Behdad Esfahbod 已提交
1217
    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
B
Behdad Esfahbod 已提交
1218 1219
  }

B
Behdad Esfahbod 已提交
1220 1221
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1222
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1223 1224 1225 1226 1227
    return_trace (c->check_struct (this) &&
		  markCoverage.sanitize (c, this) &&
		  ligatureCoverage.sanitize (c, this) &&
		  markArray.sanitize (c, this) &&
		  ligatureArray.sanitize (c, this, (unsigned int) classCount));
B
Behdad Esfahbod 已提交
1228 1229
  }

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

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

1263
  protected:
B
Behdad Esfahbod 已提交
1264 1265
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1266
  MarkLigPosFormat1	format1;
B
Behdad Esfahbod 已提交
1267 1268 1269 1270
  } u;
};


1271 1272 1273 1274
typedef AnchorMatrix Mark2Array;	/* mark2-major--
					 * in order of Mark2Coverage Index--,
					 * mark1-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1275

B
Behdad Esfahbod 已提交
1276 1277
struct MarkMarkPosFormat1
{
1278 1279 1280
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1281 1282
    (this+mark1Coverage).add_coverage (c->input);
    (this+mark2Coverage).add_coverage (c->input);
1283 1284
  }

1285 1286 1287 1288 1289
  inline const Coverage &get_coverage (void) const
  {
    return this+mark1Coverage;
  }

B
Behdad Esfahbod 已提交
1290
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1291
  {
B
Behdad Esfahbod 已提交
1292
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1293 1294
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1295
    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
1296 1297

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

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

B
Behdad Esfahbod 已提交
1305 1306
    unsigned int j = skippy_iter.idx;

B
Behdad Esfahbod 已提交
1307 1308 1309 1310
    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]);
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324

    if (likely (id1 == id2)) {
      if (id1 == 0) /* Marks belonging to the same base. */
	goto good;
      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
        goto good;
    } else {
      /* If ligature ids don't match, it may be the case that one of the marks
       * itself is a ligature.  In which case match. */
      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
	goto good;
    }

    /* Didn't match. */
B
Behdad Esfahbod 已提交
1325
    return_trace (false);
B
Behdad Esfahbod 已提交
1326

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

B
Behdad Esfahbod 已提交
1331
    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
B
Behdad Esfahbod 已提交
1332 1333
  }

B
Behdad Esfahbod 已提交
1334 1335
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1336
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1337 1338 1339 1340 1341
    return_trace (c->check_struct (this) &&
		  mark1Coverage.sanitize (c, this) &&
		  mark2Coverage.sanitize (c, this) &&
		  mark1Array.sanitize (c, this) &&
		  mark2Array.sanitize (c, this, (unsigned int) classCount));
B
Behdad Esfahbod 已提交
1342 1343
  }

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

B
Behdad Esfahbod 已提交
1365 1366
struct MarkMarkPos
{
1367
  template <typename context_t>
1368
  inline typename context_t::return_t dispatch (context_t *c) const
1369
  {
1370
    TRACE_DISPATCH (this, u.format);
1371
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1372
    switch (u.format) {
B
Behdad Esfahbod 已提交
1373 1374
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1375 1376 1377
    }
  }

1378
  protected:
B
Behdad Esfahbod 已提交
1379 1380
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1381
  MarkMarkPosFormat1	format1;
B
Behdad Esfahbod 已提交
1382 1383 1384 1385
  } u;
};


B
Minor  
Behdad Esfahbod 已提交
1386
struct ContextPos : Context {};
B
Behdad Esfahbod 已提交
1387

B
Minor  
Behdad Esfahbod 已提交
1388
struct ChainContextPos : ChainContext {};
B
Behdad Esfahbod 已提交
1389

B
Behdad Esfahbod 已提交
1390
struct ExtensionPos : Extension<ExtensionPos>
B
Behdad Esfahbod 已提交
1391
{
1392
  typedef struct PosLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
1393 1394 1395
};


1396

B
Behdad Esfahbod 已提交
1397 1398 1399 1400 1401
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
1402 1403
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
1404 1405
  friend struct PosLookup;

B
Behdad Esfahbod 已提交
1406
  enum Type {
1407 1408 1409 1410 1411 1412 1413 1414
    Single		= 1,
    Pair		= 2,
    Cursive		= 3,
    MarkBase		= 4,
    MarkLig		= 5,
    MarkMark		= 6,
    Context		= 7,
    ChainContext	= 8,
1415
    Extension		= 9
1416 1417
  };

1418
  template <typename context_t>
1419
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1420
  {
1421
    TRACE_DISPATCH (this, lookup_type);
1422
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1423
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
    case Single:		return_trace (u.single.dispatch (c));
    case Pair:			return_trace (u.pair.dispatch (c));
    case Cursive:		return_trace (u.cursive.dispatch (c));
    case MarkBase:		return_trace (u.markBase.dispatch (c));
    case MarkLig:		return_trace (u.markLig.dispatch (c));
    case MarkMark:		return_trace (u.markMark.dispatch (c));
    case Context:		return_trace (u.context.dispatch (c));
    case ChainContext:		return_trace (u.chainContext.dispatch (c));
    case Extension:		return_trace (u.extension.dispatch (c));
    default:			return_trace (c->default_return_value ());
1434
    }
1435 1436
  }

1437
  protected:
B
Behdad Esfahbod 已提交
1438
  union {
B
Minor  
Behdad Esfahbod 已提交
1439
  USHORT		sub_format;
B
Behdad Esfahbod 已提交
1440 1441 1442 1443 1444 1445
  SinglePos		single;
  PairPos		pair;
  CursivePos		cursive;
  MarkBasePos		markBase;
  MarkLigPos		markLig;
  MarkMarkPos		markMark;
1446
  ContextPos		context;
B
Behdad Esfahbod 已提交
1447 1448
  ChainContextPos	chainContext;
  ExtensionPos		extension;
B
Behdad Esfahbod 已提交
1449
  } u;
B
Behdad Esfahbod 已提交
1450
  public:
B
Minor  
Behdad Esfahbod 已提交
1451
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1452 1453 1454
};


B
Behdad Esfahbod 已提交
1455 1456
struct PosLookup : Lookup
{
1457
  inline const PosLookupSubTable& get_subtable (unsigned int i) const
1458
  { return Lookup::get_subtable<PosLookupSubTable> (i); }
B
Behdad Esfahbod 已提交
1459

B
Behdad Esfahbod 已提交
1460 1461 1462 1463 1464
  inline bool is_reverse (void) const
  {
    return false;
  }

B
Behdad Esfahbod 已提交
1465 1466 1467
  inline bool apply (hb_apply_context_t *c) const
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1468
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1469 1470
  }

B
Behdad Esfahbod 已提交
1471
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1472 1473
  {
    TRACE_COLLECT_GLYPHS (this);
B
Behdad Esfahbod 已提交
1474
    return_trace (dispatch (c));
1475 1476
  }

B
Behdad Esfahbod 已提交
1477 1478 1479
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1480 1481
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1482 1483
  }

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

B
Behdad Esfahbod 已提交
1486 1487 1488 1489 1490
  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
1491
  { return Lookup::dispatch<PosLookupSubTable> (c); }
B
Behdad Esfahbod 已提交
1492

B
Behdad Esfahbod 已提交
1493 1494
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1495
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1496 1497
    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1498
  }
B
Behdad Esfahbod 已提交
1499 1500
};

B
Behdad Esfahbod 已提交
1501
typedef OffsetListOf<PosLookup> PosLookupList;
B
Behdad Esfahbod 已提交
1502 1503

/*
B
Behdad Esfahbod 已提交
1504
 * GPOS -- The Glyph Positioning Table
B
Behdad Esfahbod 已提交
1505 1506
 */

B
Behdad Esfahbod 已提交
1507 1508
struct GPOS : GSUBGPOS
{
1509
  static const hb_tag_t tableTag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1510

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

1514
  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1515
  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
B
Behdad Esfahbod 已提交
1516

B
Behdad Esfahbod 已提交
1517 1518
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1519
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1520
    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
B
Behdad Esfahbod 已提交
1521
    const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
B
Behdad Esfahbod 已提交
1522
    return_trace (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1523
  }
1524 1525
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
1526 1527
};

B
Behdad Esfahbod 已提交
1528

1529 1530 1531
static void
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
{
1532 1533
  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
1534 1535
    return;

1536
  pos[i].attach_chain() = 0;
1537

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

1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550
  /* Stop if we see new parent in the chain. */
  if (j == new_parent)
    return;

  reverse_cursive_minor_offset (pos, j, direction, new_parent);

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

1551 1552
  pos[j].attach_chain() = -chain;
  pos[j].attach_type() = type;
1553
}
B
Behdad Esfahbod 已提交
1554 1555 1556
static void
fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
{
1557 1558
  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
B
Behdad Esfahbod 已提交
1559
    return;
B
Behdad Esfahbod 已提交
1560

1561 1562 1563
  pos[i].attach_chain() = 0;

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

B
Behdad Esfahbod 已提交
1565
  fix_cursive_minor_offset (pos, j, direction);
B
Behdad Esfahbod 已提交
1566

B
Behdad Esfahbod 已提交
1567 1568 1569 1570
  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 已提交
1571 1572 1573
}

static void
1574
fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
B
Behdad Esfahbod 已提交
1575
{
1576 1577
  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
  if (likely (!chain || 0 == (type & ATTACH_TYPE_MARK)))
B
Behdad Esfahbod 已提交
1578 1579
    return;

1580 1581
  unsigned int j = (int) i + chain;

B
Behdad Esfahbod 已提交
1582 1583 1584 1585

  pos[i].x_offset += pos[j].x_offset;
  pos[i].y_offset += pos[j].y_offset;

1586
  assert (j < i);
B
Behdad Esfahbod 已提交
1587
  if (HB_DIRECTION_IS_FORWARD (direction))
1588
    for (unsigned int k = j; k < i; k++) {
B
Behdad Esfahbod 已提交
1589 1590 1591 1592
      pos[i].x_offset -= pos[k].x_advance;
      pos[i].y_offset -= pos[k].y_advance;
    }
  else
1593
    for (unsigned int k = j + 1; k < i + 1; k++) {
B
Behdad Esfahbod 已提交
1594 1595 1596 1597 1598
      pos[i].x_offset += pos[k].x_advance;
      pos[i].y_offset += pos[k].y_advance;
    }
}

B
Behdad Esfahbod 已提交
1599
void
1600
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1601 1602
{
  buffer->clear_positions ();
1603 1604 1605

  unsigned int count = buffer->len;
  for (unsigned int i = 0; i < count; i++)
1606
    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
B
Behdad Esfahbod 已提交
1607 1608
}

B
Behdad Esfahbod 已提交
1609
void
1610
GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1611
{
1612 1613
  _hb_buffer_assert_gsubgpos_vars (buffer);

1614 1615
  unsigned int len;
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
B
Behdad Esfahbod 已提交
1616 1617
  hb_direction_t direction = buffer->props.direction;

B
Behdad Esfahbod 已提交
1618
  /* Handle cursive connections */
1619 1620 1621
  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_CURSIVE)
    for (unsigned int i = 0; i < len; i++)
      fix_cursive_minor_offset (pos, i, direction);
1622

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

B
Behdad Esfahbod 已提交
1629 1630 1631

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

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

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


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


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

B
Behdad Esfahbod 已提交
1661

1662
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */