hb-ot-layout-gpos-private.hh 45.0 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright (C) 2007,2008,2009,2010  Red Hat, Inc.
3
 * Copyright (C) 2010  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_PRIVATE_HH
#define HB_OT_LAYOUT_GPOS_PRIVATE_HH
B
Behdad Esfahbod 已提交
31

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

B
Behdad Esfahbod 已提交
34 35
HB_BEGIN_DECLS

B
Behdad Esfahbod 已提交
36

B
Behdad Esfahbod 已提交
37 38 39 40 41
/* buffer var allocations */
#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 已提交
42 43
/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */

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

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

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

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

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

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

97 98 99 100
  void apply_value (hb_ot_layout_context_t *layout,
		    const void             *base,
		    const Value            *values,
		    hb_glyph_position_t    &glyph_pos) const
B
WIP  
Behdad Esfahbod 已提交
101 102 103 104 105 106
  {
    unsigned int x_ppem, y_ppem;
    unsigned int format = *this;

    if (!format) return;

107
    /* design units -> fractional pixel */
B
Behdad Esfahbod 已提交
108 109 110 111
    if (format & xPlacement) glyph_pos.x_offset  += layout->scale_x (get_short (values++));
    if (format & yPlacement) glyph_pos.y_offset  += layout->scale_y (get_short (values++));
    if (format & xAdvance)   glyph_pos.x_advance += layout->scale_x (get_short (values++));
    if (format & yAdvance)   glyph_pos.y_advance += layout->scale_y (get_short (values++));
112

B
Behdad Esfahbod 已提交
113 114
    if (!has_device ()) return;

115 116
    x_ppem = layout->font->x_ppem;
    y_ppem = layout->font->y_ppem;
B
Behdad Esfahbod 已提交
117 118 119

    if (!x_ppem && !y_ppem) return;

120 121
    /* pixel -> fractional pixel */
    if (format & xPlaDevice) {
B
Behdad Esfahbod 已提交
122
      if (x_ppem) glyph_pos.x_offset  += (base + get_device (values++)).get_x_delta (layout); else values++;
123 124
    }
    if (format & yPlaDevice) {
B
Behdad Esfahbod 已提交
125
      if (y_ppem) glyph_pos.y_offset  += (base + get_device (values++)).get_y_delta (layout); else values++;
126 127
    }
    if (format & xAdvDevice) {
B
Behdad Esfahbod 已提交
128
      if (x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (layout); else values++;
129 130
    }
    if (format & yAdvDevice) {
B
Behdad Esfahbod 已提交
131
      if (y_ppem) glyph_pos.y_advance += (base + get_device (values++)).get_y_delta (layout); else values++;
132 133
    }
  }
B
WIP  
Behdad Esfahbod 已提交
134 135

  private:
B
Behdad Esfahbod 已提交
136
  inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
B
WIP  
Behdad Esfahbod 已提交
137 138 139 140 141 142 143
    unsigned int format = *this;

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

B
Behdad Esfahbod 已提交
144 145 146 147
    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 已提交
148 149 150 151

    return true;
  }

B
Behdad Esfahbod 已提交
152 153 154 155 156 157 158 159
  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 已提交
160 161
  public:

B
Behdad Esfahbod 已提交
162
  inline bool has_device (void) const {
B
WIP  
Behdad Esfahbod 已提交
163 164 165 166
    unsigned int format = *this;
    return (format & devices) != 0;
  }

B
Behdad Esfahbod 已提交
167
  inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
B
WIP  
Behdad Esfahbod 已提交
168
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
169 170
    return c->check_range (values, get_size ())
	&& (!has_device () || sanitize_value_devices (c, base, values));
B
WIP  
Behdad Esfahbod 已提交
171 172
  }

B
Behdad Esfahbod 已提交
173
  inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
B
WIP  
Behdad Esfahbod 已提交
174 175 176
    TRACE_SANITIZE ();
    unsigned int len = get_len ();

B
Behdad Esfahbod 已提交
177
    if (!c->check_array (values, get_size (), count)) return false;
B
WIP  
Behdad Esfahbod 已提交
178 179 180 181

    if (!has_device ()) return true;

    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
182
      if (!sanitize_value_devices (c, base, values))
B
WIP  
Behdad Esfahbod 已提交
183 184 185 186 187 188 189
        return false;
      values += len;
    }

    return true;
  }

B
Behdad Esfahbod 已提交
190
  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
B
Behdad Esfahbod 已提交
191
  inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
B
WIP  
Behdad Esfahbod 已提交
192 193 194 195 196
    TRACE_SANITIZE ();

    if (!has_device ()) return true;

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

    return true;
  }
B
Behdad Esfahbod 已提交
204 205 206
};


B
Behdad Esfahbod 已提交
207 208
struct AnchorFormat1
{
B
Behdad Esfahbod 已提交
209 210 211
  friend struct Anchor;

  private:
212
  inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
B
Behdad Esfahbod 已提交
213 214
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
215 216
      *x = layout->scale_x (xCoordinate);
      *y = layout->scale_y (yCoordinate);
B
Behdad Esfahbod 已提交
217 218
  }

B
Behdad Esfahbod 已提交
219
  inline bool sanitize (hb_sanitize_context_t *c) {
220
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
221
    return c->check_struct (this);
B
Behdad Esfahbod 已提交
222 223
  }

B
Behdad Esfahbod 已提交
224 225 226 227
  private:
  USHORT	format;			/* Format identifier--format = 1 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
228 229
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
230 231
};

B
Behdad Esfahbod 已提交
232 233
struct AnchorFormat2
{
B
Behdad Esfahbod 已提交
234 235 236
  friend struct Anchor;

  private:
237
  inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
238 239
			  hb_position_t *x, hb_position_t *y) const
  {
240 241
      unsigned int x_ppem = layout->font->x_ppem;
      unsigned int y_ppem = layout->font->y_ppem;
B
Behdad Esfahbod 已提交
242 243 244 245
      hb_position_t cx, cy;
      hb_bool_t ret;

      if (x_ppem || y_ppem)
246
	ret = hb_font_get_contour_point (layout->font, layout->face, anchorPoint, glyph_id, &cx, &cy);
B
Behdad Esfahbod 已提交
247 248
      *x = x_ppem && ret ? cx : layout->scale_x (xCoordinate);
      *y = y_ppem && ret ? cy : layout->scale_y (yCoordinate);
B
Behdad Esfahbod 已提交
249 250
  }

B
Behdad Esfahbod 已提交
251
  inline bool sanitize (hb_sanitize_context_t *c) {
252
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
253
    return c->check_struct (this);
B
Behdad Esfahbod 已提交
254 255
  }

B
Behdad Esfahbod 已提交
256 257 258 259 260
  private:
  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 */
261 262
  public:
  DEFINE_SIZE_STATIC (8);
B
Behdad Esfahbod 已提交
263 264
};

B
Behdad Esfahbod 已提交
265 266
struct AnchorFormat3
{
B
Behdad Esfahbod 已提交
267 268 269
  friend struct Anchor;

  private:
270
  inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id HB_UNUSED,
B
Behdad Esfahbod 已提交
271 272
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
273 274
      *x = layout->scale_x (xCoordinate);
      *y = layout->scale_y (yCoordinate);
275

B
Behdad Esfahbod 已提交
276
      /* pixel -> fractional pixel */
277
      if (layout->font->x_ppem)
B
Behdad Esfahbod 已提交
278
	*x += (this+xDeviceTable).get_x_delta (layout);
279
      if (layout->font->y_ppem)
B
Behdad Esfahbod 已提交
280
	*y += (this+yDeviceTable).get_x_delta (layout);
B
Behdad Esfahbod 已提交
281 282
  }

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

B
Behdad Esfahbod 已提交
290 291 292 293 294 295 296 297 298 299 300 301
  private:
  USHORT	format;			/* Format identifier--format = 3 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
  OffsetTo<Device>
		xDeviceTable;		/* Offset to Device table for X
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
  OffsetTo<Device>
		yDeviceTable;		/* Offset to Device table for Y
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
302 303
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
304 305
};

B
Behdad Esfahbod 已提交
306 307
struct Anchor
{
308
  inline void get_anchor (hb_ot_layout_context_t *layout, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
309 310
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
311 312
    *x = *y = 0;
    switch (u.format) {
B
Behdad Esfahbod 已提交
313 314 315
    case 1: u.format1.get_anchor (layout, glyph_id, x, y); return;
    case 2: u.format2.get_anchor (layout, glyph_id, x, y); return;
    case 3: u.format3.get_anchor (layout, glyph_id, x, y); return;
316
    default:						    return;
B
Behdad Esfahbod 已提交
317 318 319
    }
  }

B
Behdad Esfahbod 已提交
320
  inline bool sanitize (hb_sanitize_context_t *c) {
321
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
322
    if (!u.format.sanitize (c)) return false;
B
Behdad Esfahbod 已提交
323
    switch (u.format) {
B
Behdad Esfahbod 已提交
324 325 326
    case 1: return u.format1.sanitize (c);
    case 2: return u.format2.sanitize (c);
    case 3: return u.format3.sanitize (c);
B
Behdad Esfahbod 已提交
327 328 329 330
    default:return true;
    }
  }

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


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

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

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


B
Behdad Esfahbod 已提交
371 372
struct MarkRecord
{
373
  friend struct MarkArray;
B
Behdad Esfahbod 已提交
374

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

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

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

    const Anchor& mark_anchor = this + record.markAnchor;
    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);

    hb_position_t mark_x, mark_y, base_x, base_y;

406
    mark_anchor.get_anchor (c->layout, c->buffer->info[c->buffer->i].codepoint, &mark_x, &mark_y);
407
    glyph_anchor.get_anchor (c->layout, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
408

409
    hb_glyph_position_t &o = c->buffer->pos[c->buffer->i];
B
Behdad Esfahbod 已提交
410 411 412
    o.x_offset = base_x - mark_x;
    o.y_offset = base_y - mark_y;
    o.attach_lookback() = c->buffer->i - glyph_pos;
413

414
    c->buffer->i++;
415 416
    return true;
  }
B
Behdad Esfahbod 已提交
417

B
Behdad Esfahbod 已提交
418
  inline bool sanitize (hb_sanitize_context_t *c) {
419
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
420
    return ArrayOf<MarkRecord>::sanitize (c, this);
B
Behdad Esfahbod 已提交
421
  }
B
Behdad Esfahbod 已提交
422 423 424 425 426
};


/* Lookups */

B
Behdad Esfahbod 已提交
427 428
struct SinglePosFormat1
{
B
Behdad Esfahbod 已提交
429 430 431
  friend struct SinglePos;

  private:
B
Behdad Esfahbod 已提交
432
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
433
  {
434
    TRACE_APPLY ();
435
    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
436
    if (likely (index == NOT_COVERED))
437 438
      return false;

439
    valueFormat.apply_value (c->layout, this, values, c->buffer->pos[c->buffer->i]);
440

441
    c->buffer->i++;
442
    return true;
B
Behdad Esfahbod 已提交
443 444
  }

B
Behdad Esfahbod 已提交
445
  inline bool sanitize (hb_sanitize_context_t *c) {
446
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
447 448 449
    return c->check_struct (this)
	&& coverage.sanitize (c, this)
	&& valueFormat.sanitize_value (c, this, values);
B
Behdad Esfahbod 已提交
450 451
  }

B
Behdad Esfahbod 已提交
452 453 454 455 456
  private:
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
457
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
458 459 460 461
					 * ValueRecord */
  ValueRecord	values;			/* Defines positioning
					 * value(s)--applied to all glyphs in
					 * the Coverage table */
B
Behdad Esfahbod 已提交
462
  public:
463
  DEFINE_SIZE_ARRAY (6, values);
B
Behdad Esfahbod 已提交
464 465
};

B
Behdad Esfahbod 已提交
466 467
struct SinglePosFormat2
{
B
Behdad Esfahbod 已提交
468 469 470
  friend struct SinglePos;

  private:
B
Behdad Esfahbod 已提交
471
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
472
  {
473
    TRACE_APPLY ();
474
    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
475
    if (likely (index == NOT_COVERED))
476 477
      return false;

478
    if (likely (index >= valueCount))
479 480
      return false;

B
Behdad Esfahbod 已提交
481
    valueFormat.apply_value (c->layout, this,
B
Behdad Esfahbod 已提交
482
			     &values[index * valueFormat.get_len ()],
483
			     c->buffer->pos[c->buffer->i]);
484

485
    c->buffer->i++;
486
    return true;
B
Behdad Esfahbod 已提交
487 488
  }

B
Behdad Esfahbod 已提交
489
  inline bool sanitize (hb_sanitize_context_t *c) {
490
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
491 492 493
    return c->check_struct (this)
	&& coverage.sanitize (c, this)
	&& valueFormat.sanitize_values (c, this, values, valueCount);
B
Behdad Esfahbod 已提交
494 495
  }

B
Behdad Esfahbod 已提交
496 497 498 499 500
  private:
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
501
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
502 503 504 505
					 * ValueRecord */
  USHORT	valueCount;		/* Number of ValueRecords */
  ValueRecord	values;			/* Array of ValueRecords--positioning
					 * values applied to glyphs */
B
Behdad Esfahbod 已提交
506
  public:
507
  DEFINE_SIZE_ARRAY (8, values);
B
Behdad Esfahbod 已提交
508 509
};

B
Behdad Esfahbod 已提交
510 511
struct SinglePos
{
B
Behdad Esfahbod 已提交
512 513 514
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
515
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
516
  {
517
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
518
    switch (u.format) {
B
Behdad Esfahbod 已提交
519 520
    case 1: return u.format1.apply (c);
    case 2: return u.format2.apply (c);
B
Behdad Esfahbod 已提交
521 522 523 524
    default:return false;
    }
  }

B
Behdad Esfahbod 已提交
525
  inline bool sanitize (hb_sanitize_context_t *c) {
526
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
527
    if (!u.format.sanitize (c)) return false;
B
Behdad Esfahbod 已提交
528
    switch (u.format) {
B
Behdad Esfahbod 已提交
529 530
    case 1: return u.format1.sanitize (c);
    case 2: return u.format2.sanitize (c);
B
Behdad Esfahbod 已提交
531 532 533 534
    default:return true;
    }
  }

B
Behdad Esfahbod 已提交
535 536 537
  private:
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
538 539
  SinglePosFormat1	format1;
  SinglePosFormat2	format2;
B
Behdad Esfahbod 已提交
540 541 542 543
  } u;
};


B
Behdad Esfahbod 已提交
544 545
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
546
  friend struct PairSet;
B
Behdad Esfahbod 已提交
547 548 549 550 551 552 553

  private:
  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 已提交
554
  public:
555
  DEFINE_SIZE_ARRAY (2, values);
B
Behdad Esfahbod 已提交
556 557
};

B
Behdad Esfahbod 已提交
558 559
struct PairSet
{
B
Behdad Esfahbod 已提交
560 561
  friend struct PairPosFormat1;

B
Behdad Esfahbod 已提交
562
  inline bool apply (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
563 564 565 566 567 568 569 570 571 572 573 574
		     const ValueFormat *valueFormats,
		     unsigned int pos) const
  {
    TRACE_APPLY ();
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);

    unsigned int count = len;
    const PairValueRecord *record = CastP<PairValueRecord> (array);
    for (unsigned int i = 0; i < count; i++)
    {
575
      if (c->buffer->info[pos].codepoint == record->secondGlyph)
B
Behdad Esfahbod 已提交
576
      {
577
	valueFormats[0].apply_value (c->layout, this, &record->values[0], c->buffer->pos[c->buffer->i]);
578
	valueFormats[1].apply_value (c->layout, this, &record->values[len1], c->buffer->pos[pos]);
B
Behdad Esfahbod 已提交
579 580
	if (len2)
	  pos++;
581
	c->buffer->i = pos;
B
Behdad Esfahbod 已提交
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
	return true;
      }
      record = &StructAtOffset<PairValueRecord> (record, record_size);
    }

    return false;
  }

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

B
Behdad Esfahbod 已提交
597
  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
598
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
599 600
    if (!(c->check_struct (this)
       && c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
B
Behdad Esfahbod 已提交
601 602 603

    unsigned int count = len;
    PairValueRecord *record = CastP<PairValueRecord> (array);
B
Behdad Esfahbod 已提交
604 605
    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 已提交
606 607
  }

B
Behdad Esfahbod 已提交
608 609
  private:
  USHORT	len;			/* Number of PairValueRecords */
610
  USHORT	array[VAR];		/* Array of PairValueRecords--ordered
B
Behdad Esfahbod 已提交
611
					 * by GlyphID of the second glyph */
B
Behdad Esfahbod 已提交
612
  public:
613
  DEFINE_SIZE_ARRAY (2, array);
B
Behdad Esfahbod 已提交
614
};
B
Behdad Esfahbod 已提交
615

B
Behdad Esfahbod 已提交
616 617
struct PairPosFormat1
{
B
Behdad Esfahbod 已提交
618 619 620
  friend struct PairPos;

  private:
B
Behdad Esfahbod 已提交
621
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
622
  {
623
    TRACE_APPLY ();
624 625
    unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
    if (unlikely (c->buffer->i + 2 > end))
B
Behdad Esfahbod 已提交
626 627
      return false;

628
    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
629
    if (likely (index == NOT_COVERED))
B
Behdad Esfahbod 已提交
630 631
      return false;

632
    unsigned int j = c->buffer->i + 1;
633
    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
B
Behdad Esfahbod 已提交
634
    {
635
      if (unlikely (j == end))
B
Behdad Esfahbod 已提交
636 637 638 639
	return false;
      j++;
    }

B
Behdad Esfahbod 已提交
640
    return (this+pairSet[index]).apply (c, &valueFormat1, j);
B
Behdad Esfahbod 已提交
641 642
  }

B
Behdad Esfahbod 已提交
643
  inline bool sanitize (hb_sanitize_context_t *c) {
644
    TRACE_SANITIZE ();
645 646 647

    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
B
Behdad Esfahbod 已提交
648 649 650 651 652 653
    PairSet::sanitize_closure_t closure = {
      this,
      &valueFormat1,
      len1,
      1 + len1 + len2
    };
654

B
Behdad Esfahbod 已提交
655 656 657
    return c->check_struct (this)
	&& coverage.sanitize (c, this)
	&& pairSet.sanitize (c, this, &closure);
B
Behdad Esfahbod 已提交
658 659
  }

B
Behdad Esfahbod 已提交
660 661 662 663 664
  private:
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
665
  ValueFormat	valueFormat1;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
666 667
					 * ValueRecord1--for the first glyph
					 * in the pair--may be zero (0) */
668
  ValueFormat	valueFormat2;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
669 670 671 672 673
					 * ValueRecord2--for the second glyph
					 * in the pair--may be zero (0) */
  OffsetArrayOf<PairSet>
		pairSet;		/* Array of PairSet tables
					 * ordered by Coverage Index */
674
  public:
675
  DEFINE_SIZE_ARRAY (10, pairSet);
B
Behdad Esfahbod 已提交
676 677
};

B
Behdad Esfahbod 已提交
678 679
struct PairPosFormat2
{
B
Behdad Esfahbod 已提交
680 681 682
  friend struct PairPos;

  private:
B
Behdad Esfahbod 已提交
683
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
684
  {
685
    TRACE_APPLY ();
686 687
    unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
    if (unlikely (c->buffer->i + 2 > end))
B
Behdad Esfahbod 已提交
688 689
      return false;

690
    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoint);
691
    if (likely (index == NOT_COVERED))
B
Behdad Esfahbod 已提交
692 693
      return false;

694
    unsigned int j = c->buffer->i + 1;
695
    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
B
Behdad Esfahbod 已提交
696
    {
697
      if (unlikely (j == end))
B
Behdad Esfahbod 已提交
698 699 700 701 702 703 704 705
	return false;
      j++;
    }

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

706
    unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->i].codepoint);
707
    unsigned int klass2 = (this+classDef2) (c->buffer->info[j].codepoint);
708
    if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
B
Behdad Esfahbod 已提交
709 710
      return false;

B
Behdad Esfahbod 已提交
711
    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
712
    valueFormat1.apply_value (c->layout, this, v, c->buffer->pos[c->buffer->i]);
713
    valueFormat2.apply_value (c->layout, this, v + len1, c->buffer->pos[j]);
B
Behdad Esfahbod 已提交
714 715 716

    if (len2)
      j++;
717
    c->buffer->i = j;
B
Behdad Esfahbod 已提交
718 719

    return true;
B
Behdad Esfahbod 已提交
720 721
  }

B
Behdad Esfahbod 已提交
722
  inline bool sanitize (hb_sanitize_context_t *c) {
723
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
724 725 726 727
    if (!(c->check_struct (this)
       && coverage.sanitize (c, this)
       && classDef1.sanitize (c, this)
       && classDef2.sanitize (c, this))) return false;
728

729 730 731
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int stride = len1 + len2;
B
Behdad Esfahbod 已提交
732
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
733
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
B
Behdad Esfahbod 已提交
734 735 736
    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 已提交
737
  }
B
Behdad Esfahbod 已提交
738

B
Behdad Esfahbod 已提交
739 740 741 742 743
  private:
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
744
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
745 746
					 * first glyph of the pair--may be zero
					 * (0) */
747
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764
					 * 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 已提交
765
  public:
766
  DEFINE_SIZE_ARRAY (16, values);
B
Behdad Esfahbod 已提交
767 768
};

B
Behdad Esfahbod 已提交
769 770
struct PairPos
{
B
Behdad Esfahbod 已提交
771 772 773
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
774
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
775
  {
776
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
777
    switch (u.format) {
B
Behdad Esfahbod 已提交
778 779
    case 1: return u.format1.apply (c);
    case 2: return u.format2.apply (c);
B
Behdad Esfahbod 已提交
780 781 782 783
    default:return false;
    }
  }

B
Behdad Esfahbod 已提交
784
  inline bool sanitize (hb_sanitize_context_t *c) {
785
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
786
    if (!u.format.sanitize (c)) return false;
B
Behdad Esfahbod 已提交
787
    switch (u.format) {
B
Behdad Esfahbod 已提交
788 789
    case 1: return u.format1.sanitize (c);
    case 2: return u.format2.sanitize (c);
B
Behdad Esfahbod 已提交
790 791 792 793
    default:return true;
    }
  }

B
Behdad Esfahbod 已提交
794 795 796
  private:
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
797 798
  PairPosFormat1	format1;
  PairPosFormat2	format2;
B
Behdad Esfahbod 已提交
799 800 801 802
  } u;
};


B
Behdad Esfahbod 已提交
803 804
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
805 806
  friend struct CursivePosFormat1;

B
Behdad Esfahbod 已提交
807
  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
808
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
809 810
    return entryAnchor.sanitize (c, base)
	&& exitAnchor.sanitize (c, base);
B
Behdad Esfahbod 已提交
811 812
  }

B
Behdad Esfahbod 已提交
813
  private:
B
Behdad Esfahbod 已提交
814 815 816 817 818 819 820 821
  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 已提交
822 823
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
824 825
};

B
Behdad Esfahbod 已提交
826 827
struct CursivePosFormat1
{
B
Behdad Esfahbod 已提交
828 829 830
  friend struct CursivePos;

  private:
B
Behdad Esfahbod 已提交
831
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
832
  {
833
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
834 835

    /* We don't handle mark glyphs here. */
836
    if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
B
Behdad Esfahbod 已提交
837 838
      return false;

839 840
    unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length);
    if (unlikely (c->buffer->i + 2 > end))
B
Behdad Esfahbod 已提交
841 842
      return false;

843 844 845 846 847
    const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->i].codepoint)];
    if (!this_record.exitAnchor)
      return false;

    unsigned int j = c->buffer->i + 1;
848
    while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, NULL))
849 850 851 852 853 854 855 856 857
    {
      if (unlikely (j == end))
	return false;
      j++;
    }

    const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[j].codepoint)];
    if (!next_record.entryAnchor)
      return false;
B
Behdad Esfahbod 已提交
858

859
    unsigned int i = c->buffer->i;
B
Behdad Esfahbod 已提交
860

861 862 863
    hb_position_t entry_x, entry_y, exit_x, exit_y;
    (this+this_record.exitAnchor).get_anchor (c->layout, c->buffer->info[i].codepoint, &exit_x, &exit_y);
    (this+next_record.entryAnchor).get_anchor (c->layout, c->buffer->info[j].codepoint, &entry_x, &entry_y);
B
Behdad Esfahbod 已提交
864

865
    hb_direction_t direction = c->buffer->props.direction;
B
Behdad Esfahbod 已提交
866

867 868 869
    /* Align the exit anchor of the left/top glyph with the entry anchor of the right/bottom glyph
     * by adjusting advance of the left/top glyph. */
    if (HB_DIRECTION_IS_BACKWARD (direction))
B
Behdad Esfahbod 已提交
870
    {
871 872 873 874
      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
	c->buffer->pos[j].x_advance = c->buffer->pos[j].x_offset + entry_x - exit_x;
      else
	c->buffer->pos[j].y_advance = c->buffer->pos[j].y_offset + entry_y - exit_y;
B
Behdad Esfahbod 已提交
875 876 877
    }
    else
    {
878 879 880 881
      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
	c->buffer->pos[i].x_advance = c->buffer->pos[i].x_offset + exit_x - entry_x;
      else
	c->buffer->pos[i].y_advance = c->buffer->pos[i].y_offset + exit_y - entry_y;
B
Behdad Esfahbod 已提交
882 883
    }

884
    if  (c->lookup_props & LookupFlag::RightToLeft)
B
Behdad Esfahbod 已提交
885
    {
886
      c->buffer->pos[i].cursive_chain() = j - i;
887 888 889 890
      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
	c->buffer->pos[i].y_offset = entry_y - exit_y;
      else
	c->buffer->pos[i].x_offset = entry_x - exit_x;
B
Behdad Esfahbod 已提交
891 892 893
    }
    else
    {
894
      c->buffer->pos[j].cursive_chain() = i - j;
895 896 897 898
      if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
	c->buffer->pos[j].y_offset = exit_y - entry_y;
      else
	c->buffer->pos[j].x_offset = exit_x - entry_x;
B
Behdad Esfahbod 已提交
899 900
    }

901
    c->buffer->i = j;
B
Behdad Esfahbod 已提交
902
    return true;
B
Behdad Esfahbod 已提交
903 904
  }

B
Behdad Esfahbod 已提交
905
  inline bool sanitize (hb_sanitize_context_t *c) {
906
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
907 908
    return coverage.sanitize (c, this)
	&& entryExitRecord.sanitize (c, this);
B
Behdad Esfahbod 已提交
909 910
  }

B
Behdad Esfahbod 已提交
911 912 913 914 915 916 917 918
  private:
  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 */
919
  public:
920
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
B
Behdad Esfahbod 已提交
921 922
};

B
Behdad Esfahbod 已提交
923 924
struct CursivePos
{
B
Behdad Esfahbod 已提交
925 926 927
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
928
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
929
  {
930
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
931
    switch (u.format) {
B
Behdad Esfahbod 已提交
932
    case 1: return u.format1.apply (c);
B
Behdad Esfahbod 已提交
933 934 935 936
    default:return false;
    }
  }

B
Behdad Esfahbod 已提交
937
  inline bool sanitize (hb_sanitize_context_t *c) {
938
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
939
    if (!u.format.sanitize (c)) return false;
B
Behdad Esfahbod 已提交
940
    switch (u.format) {
B
Behdad Esfahbod 已提交
941
    case 1: return u.format1.sanitize (c);
B
Behdad Esfahbod 已提交
942 943 944 945
    default:return true;
    }
  }

B
Behdad Esfahbod 已提交
946 947 948
  private:
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
949
  CursivePosFormat1	format1;
B
Behdad Esfahbod 已提交
950 951 952 953
  } u;
};


954 955 956
typedef AnchorMatrix BaseArray;		/* base-major--
					 * in order of BaseCoverage Index--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
957
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
958

B
Behdad Esfahbod 已提交
959 960
struct MarkBasePosFormat1
{
B
Behdad Esfahbod 已提交
961 962 963
  friend struct MarkBasePos;

  private:
B
Behdad Esfahbod 已提交
964
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
965
  {
966
    TRACE_APPLY ();
967
    unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
968
    if (likely (mark_index == NOT_COVERED))
B
Behdad Esfahbod 已提交
969 970 971
      return false;

    /* now we search backwards for a non-mark glyph */
972
    unsigned int property;
973
    unsigned int j = c->buffer->i;
974
    do
B
Behdad Esfahbod 已提交
975
    {
976
      if (unlikely (!j))
B
Behdad Esfahbod 已提交
977
	return false;
B
Behdad Esfahbod 已提交
978
      j--;
979
    } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
980

981 982
    /* The following assertion is too strong, so we've disabled it. */
    if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
B
Behdad Esfahbod 已提交
983 984
      return false;

985
    unsigned int base_index = (this+baseCoverage) (c->buffer->info[j].codepoint);
B
Behdad Esfahbod 已提交
986
    if (base_index == NOT_COVERED)
B
Behdad Esfahbod 已提交
987 988
      return false;

B
Behdad Esfahbod 已提交
989
    return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, j);
B
Behdad Esfahbod 已提交
990 991
  }

B
Behdad Esfahbod 已提交
992
  inline bool sanitize (hb_sanitize_context_t *c) {
993
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
994 995 996 997 998
    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 已提交
999 1000
  }

B
Behdad Esfahbod 已提交
1001 1002
  private:
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1003 1004
  OffsetTo<Coverage>
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
1005
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1006 1007
  OffsetTo<Coverage>
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
1008 1009
					 * beginning of MarkBasePos subtable */
  USHORT	classCount;		/* Number of classes defined for marks */
B
Behdad Esfahbod 已提交
1010 1011
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1012
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
1013 1014
  OffsetTo<BaseArray>
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
1015
					 * beginning of MarkBasePos subtable */
1016 1017
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1018 1019
};

B
Behdad Esfahbod 已提交
1020 1021
struct MarkBasePos
{
B
Behdad Esfahbod 已提交
1022 1023 1024
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1025
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1026
  {
1027
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
1028
    switch (u.format) {
B
Behdad Esfahbod 已提交
1029
    case 1: return u.format1.apply (c);
B
Behdad Esfahbod 已提交
1030 1031 1032 1033
    default:return false;
    }
  }

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

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


1051 1052 1053
typedef AnchorMatrix LigatureAttach;	/* component-major--
					 * in order of writing direction--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1054
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1055

1056
typedef OffsetListOf<LigatureAttach> LigatureArray;
B
Behdad Esfahbod 已提交
1057
					/* Array of LigatureAttach
B
Behdad Esfahbod 已提交
1058 1059 1060
					 * tables ordered by
					 * LigatureCoverage Index */

B
Behdad Esfahbod 已提交
1061 1062
struct MarkLigPosFormat1
{
B
Behdad Esfahbod 已提交
1063 1064 1065
  friend struct MarkLigPos;

  private:
B
Behdad Esfahbod 已提交
1066
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1067
  {
1068
    TRACE_APPLY ();
1069
    unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->i].codepoint);
1070
    if (likely (mark_index == NOT_COVERED))
B
Behdad Esfahbod 已提交
1071 1072 1073
      return false;

    /* now we search backwards for a non-mark glyph */
1074
    unsigned int property;
1075
    unsigned int j = c->buffer->i;
1076
    do
B
Behdad Esfahbod 已提交
1077
    {
1078
      if (unlikely (!j))
B
Behdad Esfahbod 已提交
1079
	return false;
B
Behdad Esfahbod 已提交
1080
      j--;
1081
    } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], LookupFlag::IgnoreMarks, &property));
1082

1083 1084
    /* The following assertion is too strong, so we've disabled it. */
    if (false && !(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
B
Behdad Esfahbod 已提交
1085 1086
      return false;

1087
    unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
B
Behdad Esfahbod 已提交
1088 1089 1090 1091
    if (lig_index == NOT_COVERED)
      return false;

    const LigatureArray& lig_array = this+ligatureArray;
1092
    const LigatureAttach& lig_attach = lig_array[lig_index];
1093 1094

    /* Find component to attach to */
B
Behdad Esfahbod 已提交
1095
    unsigned int comp_count = lig_attach.rows;
1096
    if (unlikely (!comp_count))
B
Behdad Esfahbod 已提交
1097 1098 1099 1100 1101 1102
      return false;
    unsigned int comp_index;
    /* 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. */
1103
    if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer->info[c->buffer->i].lig_id() && c->buffer->info[c->buffer->i].component())
B
Behdad Esfahbod 已提交
1104
    {
1105
      comp_index = c->buffer->info[c->buffer->i].component() - 1;
B
Behdad Esfahbod 已提交
1106 1107
      if (comp_index >= comp_count)
	comp_index = comp_count - 1;
B
Behdad Esfahbod 已提交
1108 1109
    }
    else
B
Behdad Esfahbod 已提交
1110
      comp_index = comp_count - 1;
B
Behdad Esfahbod 已提交
1111

B
Behdad Esfahbod 已提交
1112
    return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
B
Behdad Esfahbod 已提交
1113 1114
  }

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

B
Behdad Esfahbod 已提交
1124 1125
  private:
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1126 1127
  OffsetTo<Coverage>
		markCoverage;		/* Offset to Mark Coverage table--from
B
Behdad Esfahbod 已提交
1128
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1129 1130
  OffsetTo<Coverage>
		ligatureCoverage;	/* Offset to Ligature Coverage
B
Behdad Esfahbod 已提交
1131 1132 1133
					 * table--from beginning of MarkLigPos
					 * subtable */
  USHORT	classCount;		/* Number of defined mark classes */
B
Behdad Esfahbod 已提交
1134 1135
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
1136
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
1137 1138
  OffsetTo<LigatureArray>
		ligatureArray;		/* Offset to LigatureArray table--from
B
Behdad Esfahbod 已提交
1139
					 * beginning of MarkLigPos subtable */
1140 1141
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1142 1143
};

B
Behdad Esfahbod 已提交
1144 1145
struct MarkLigPos
{
B
Behdad Esfahbod 已提交
1146 1147 1148
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1149
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1150
  {
1151
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
1152
    switch (u.format) {
B
Behdad Esfahbod 已提交
1153
    case 1: return u.format1.apply (c);
B
Behdad Esfahbod 已提交
1154 1155 1156 1157
    default:return false;
    }
  }

B
Behdad Esfahbod 已提交
1158
  inline bool sanitize (hb_sanitize_context_t *c) {
1159
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
1160
    if (!u.format.sanitize (c)) return false;
B
Behdad Esfahbod 已提交
1161
    switch (u.format) {
B
Behdad Esfahbod 已提交
1162
    case 1: return u.format1.sanitize (c);
B
Behdad Esfahbod 已提交
1163 1164 1165 1166
    default:return true;
    }
  }

B
Behdad Esfahbod 已提交
1167 1168 1169
  private:
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1170
  MarkLigPosFormat1	format1;
B
Behdad Esfahbod 已提交
1171 1172 1173 1174
  } u;
};


1175 1176 1177 1178
typedef AnchorMatrix Mark2Array;	/* mark2-major--
					 * in order of Mark2Coverage Index--,
					 * mark1-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1179

B
Behdad Esfahbod 已提交
1180 1181
struct MarkMarkPosFormat1
{
B
Behdad Esfahbod 已提交
1182 1183 1184
  friend struct MarkMarkPos;

  private:
B
Behdad Esfahbod 已提交
1185
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1186
  {
1187
    TRACE_APPLY ();
1188
    unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->i].codepoint);
1189
    if (likely (mark1_index == NOT_COVERED))
B
Behdad Esfahbod 已提交
1190 1191 1192
      return false;

    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1193
    unsigned int property;
1194
    unsigned int j = c->buffer->i;
1195
    do
B
Behdad Esfahbod 已提交
1196
    {
1197
      if (unlikely (!j))
B
Behdad Esfahbod 已提交
1198
	return false;
B
Behdad Esfahbod 已提交
1199
      j--;
1200
    } while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->lookup_props, &property));
1201

B
Behdad Esfahbod 已提交
1202 1203 1204 1205
    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
      return false;

    /* Two marks match only if they belong to the same base, or same component
1206 1207
     * of the same ligature.  That is, the component numbers must match, and
     * if those are non-zero, the ligid number should also match. */
1208 1209
    if ((c->buffer->info[j].component() != c->buffer->info[c->buffer->i].component()) ||
	(c->buffer->info[j].component() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->i].lig_id()))
B
Behdad Esfahbod 已提交
1210 1211
      return false;

1212
    unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
B
Behdad Esfahbod 已提交
1213 1214 1215
    if (mark2_index == NOT_COVERED)
      return false;

B
Behdad Esfahbod 已提交
1216
    return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
B
Behdad Esfahbod 已提交
1217 1218
  }

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

B
Behdad Esfahbod 已提交
1228 1229
  private:
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1230 1231
  OffsetTo<Coverage>
		mark1Coverage;		/* Offset to Combining Mark1 Coverage
B
Behdad Esfahbod 已提交
1232 1233
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1234 1235
  OffsetTo<Coverage>
		mark2Coverage;		/* Offset to Combining Mark2 Coverage
B
Behdad Esfahbod 已提交
1236 1237
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1238 1239 1240 1241 1242 1243 1244
  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 */
1245 1246
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
1247 1248
};

B
Behdad Esfahbod 已提交
1249 1250
struct MarkMarkPos
{
B
Behdad Esfahbod 已提交
1251 1252 1253
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1254
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1255
  {
1256
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
1257
    switch (u.format) {
B
Behdad Esfahbod 已提交
1258
    case 1: return u.format1.apply (c);
B
Behdad Esfahbod 已提交
1259 1260 1261 1262
    default:return false;
    }
  }

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

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


B
Behdad Esfahbod 已提交
1280
HB_BEGIN_DECLS
B
Behdad Esfahbod 已提交
1281
static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1282
HB_END_DECLS
B
Behdad Esfahbod 已提交
1283

B
Behdad Esfahbod 已提交
1284 1285
struct ContextPos : Context
{
1286 1287 1288
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1289
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1290
  {
1291
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
1292
    return Context::apply (c, position_lookup);
B
Behdad Esfahbod 已提交
1293
  }
B
Behdad Esfahbod 已提交
1294 1295
};

B
Behdad Esfahbod 已提交
1296 1297
struct ChainContextPos : ChainContext
{
1298 1299 1300
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1301
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1302
  {
1303
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
1304
    return ChainContext::apply (c, position_lookup);
B
Behdad Esfahbod 已提交
1305
  }
B
Behdad Esfahbod 已提交
1306 1307 1308
};


1309
struct ExtensionPos : Extension
B
Behdad Esfahbod 已提交
1310
{
B
Behdad Esfahbod 已提交
1311 1312 1313
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1314
  inline const struct PosLookupSubTable& get_subtable (void) const
B
Behdad Esfahbod 已提交
1315 1316
  {
    unsigned int offset = get_offset ();
1317
    if (unlikely (!offset)) return Null(PosLookupSubTable);
1318
    return StructAtOffset<PosLookupSubTable> (this, offset);
B
Behdad Esfahbod 已提交
1319
  }
B
Behdad Esfahbod 已提交
1320

B
Behdad Esfahbod 已提交
1321
  inline bool apply (hb_apply_context_t *c) const;
B
Behdad Esfahbod 已提交
1322

B
Behdad Esfahbod 已提交
1323
  inline bool sanitize (hb_sanitize_context_t *c);
B
Behdad Esfahbod 已提交
1324 1325 1326
};


1327

B
Behdad Esfahbod 已提交
1328 1329 1330 1331 1332
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
1333 1334
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
1335 1336
  friend struct PosLookup;

1337 1338 1339 1340 1341 1342 1343 1344 1345
  enum {
    Single		= 1,
    Pair		= 2,
    Cursive		= 3,
    MarkBase		= 4,
    MarkLig		= 5,
    MarkMark		= 6,
    Context		= 7,
    ChainContext	= 8,
1346
    Extension		= 9
1347 1348
  };

B
Behdad Esfahbod 已提交
1349
  inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
B
Behdad Esfahbod 已提交
1350
  {
1351
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
1352
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1353 1354 1355 1356 1357 1358 1359 1360 1361
    case Single:		return u.single.apply (c);
    case Pair:			return u.pair.apply (c);
    case Cursive:		return u.cursive.apply (c);
    case MarkBase:		return u.markBase.apply (c);
    case MarkLig:		return u.markLig.apply (c);
    case MarkMark:		return u.markMark.apply (c);
    case Context:		return u.c.apply (c);
    case ChainContext:		return u.chainContext.apply (c);
    case Extension:		return u.extension.apply (c);
B
Behdad Esfahbod 已提交
1362 1363 1364 1365
    default:return false;
    }
  }

B
Behdad Esfahbod 已提交
1366
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1367
    TRACE_SANITIZE ();
1368
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1369 1370 1371 1372 1373 1374 1375 1376 1377
    case Single:		return u.single.sanitize (c);
    case Pair:			return u.pair.sanitize (c);
    case Cursive:		return u.cursive.sanitize (c);
    case MarkBase:		return u.markBase.sanitize (c);
    case MarkLig:		return u.markLig.sanitize (c);
    case MarkMark:		return u.markMark.sanitize (c);
    case Context:		return u.c.sanitize (c);
    case ChainContext:		return u.chainContext.sanitize (c);
    case Extension:		return u.extension.sanitize (c);
B
Behdad Esfahbod 已提交
1378 1379 1380 1381
    default:return true;
    }
  }

B
Behdad Esfahbod 已提交
1382 1383
  private:
  union {
1384
  USHORT		sub_format;
B
Behdad Esfahbod 已提交
1385 1386 1387 1388 1389 1390
  SinglePos		single;
  PairPos		pair;
  CursivePos		cursive;
  MarkBasePos		markBase;
  MarkLigPos		markLig;
  MarkMarkPos		markMark;
B
Behdad Esfahbod 已提交
1391
  ContextPos		c;
B
Behdad Esfahbod 已提交
1392 1393
  ChainContextPos	chainContext;
  ExtensionPos		extension;
B
Behdad Esfahbod 已提交
1394
  } u;
B
Behdad Esfahbod 已提交
1395
  public:
1396
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1397 1398 1399
};


B
Behdad Esfahbod 已提交
1400 1401 1402
struct PosLookup : Lookup
{
  inline const PosLookupSubTable& get_subtable (unsigned int i) const
1403
  { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
B
Behdad Esfahbod 已提交
1404

1405
  inline bool apply_once (hb_ot_layout_context_t *layout,
B
Behdad Esfahbod 已提交
1406 1407 1408 1409
			  hb_buffer_t *buffer,
			  hb_mask_t lookup_mask,
			  unsigned int context_length,
			  unsigned int nesting_level_left) const
B
Behdad Esfahbod 已提交
1410
  {
B
Behdad Esfahbod 已提交
1411
    unsigned int lookup_type = get_type ();
B
Behdad Esfahbod 已提交
1412
    hb_apply_context_t c[1] = {{0}};
1413

B
Behdad Esfahbod 已提交
1414 1415
    c->layout = layout;
    c->buffer = buffer;
B
Behdad Esfahbod 已提交
1416
    c->lookup_mask = lookup_mask;
B
Behdad Esfahbod 已提交
1417 1418
    c->context_length = context_length;
    c->nesting_level_left = nesting_level_left;
1419
    c->lookup_props = get_props ();
1420

1421
    if (!_hb_ot_layout_check_glyph_property (c->layout->face, &c->buffer->info[c->buffer->i], c->lookup_props, &c->property))
1422
      return false;
B
Behdad Esfahbod 已提交
1423 1424

    for (unsigned int i = 0; i < get_subtable_count (); i++)
B
Behdad Esfahbod 已提交
1425
      if (get_subtable (i).apply (c, lookup_type))
B
Behdad Esfahbod 已提交
1426 1427 1428 1429 1430
	return true;

    return false;
  }

1431
   inline bool apply_string (hb_ot_layout_context_t *layout,
B
Behdad Esfahbod 已提交
1432 1433
			     hb_buffer_t *buffer,
			     hb_mask_t    mask) const
B
Behdad Esfahbod 已提交
1434
  {
B
Behdad Esfahbod 已提交
1435 1436
    bool ret = false;

1437
    if (unlikely (!buffer->len))
B
Behdad Esfahbod 已提交
1438 1439
      return false;

1440 1441
    buffer->i = 0;
    while (buffer->i < buffer->len)
B
Behdad Esfahbod 已提交
1442
    {
1443 1444 1445
      if ((buffer->info[buffer->i].mask & mask) &&
	  apply_once (layout, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
	ret = true;
B
Behdad Esfahbod 已提交
1446
      else
1447
	buffer->i++;
B
Behdad Esfahbod 已提交
1448 1449 1450 1451
    }

    return ret;
  }
B
Behdad Esfahbod 已提交
1452

B
Behdad Esfahbod 已提交
1453
  inline bool sanitize (hb_sanitize_context_t *c) {
1454
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
1455
    if (unlikely (!Lookup::sanitize (c))) return false;
1456
    OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
B
Behdad Esfahbod 已提交
1457
    return list.sanitize (c, this, get_type ());
B
Behdad Esfahbod 已提交
1458
  }
B
Behdad Esfahbod 已提交
1459 1460
};

B
Behdad Esfahbod 已提交
1461
typedef OffsetListOf<PosLookup> PosLookupList;
B
Behdad Esfahbod 已提交
1462 1463 1464 1465 1466

/*
 * GPOS
 */

B
Behdad Esfahbod 已提交
1467 1468
struct GPOS : GSUBGPOS
{
B
Behdad Esfahbod 已提交
1469
  static const hb_tag_t Tag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1470

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

1474
  inline bool position_lookup (hb_ot_layout_context_t *layout,
1475 1476 1477
			       hb_buffer_t  *buffer,
			       unsigned int  lookup_index,
			       hb_mask_t     mask) const
1478
  { return get_lookup (lookup_index).apply_string (layout, buffer, mask); }
B
Behdad Esfahbod 已提交
1479

B
Behdad Esfahbod 已提交
1480 1481
  static inline void position_finish (hb_buffer_t *buffer);

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

B
Behdad Esfahbod 已提交
1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529
void
GPOS::position_finish (hb_buffer_t *buffer)
{
  unsigned int i, j;
  unsigned int len = hb_buffer_get_length (buffer);
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer);
  hb_direction_t direction = buffer->props.direction;

  /* Handle cursive connections:
   * First handle all chain-back connections, then handle all chain-forward connections. */
  if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
  {
    for (j = 0; j < len; j++) {
      if (pos[j].cursive_chain() < 0)
	pos[j].y_offset += pos[j + pos[j].cursive_chain()].y_offset;
    }
    for (i = len; i > 0; i--) {
      j = i - 1;
      if (pos[j].cursive_chain() > 0)
	pos[j].y_offset += pos[j + pos[j].cursive_chain()].y_offset;
    }
  }
  else
  {
    for (j = 0; j < len; j++) {
      if (pos[j].cursive_chain() < 0)
	pos[j].x_offset += pos[j + pos[j].cursive_chain()].x_offset;
    }
    for (i = len; i > 0; i--) {
      j = i - 1;
      if (pos[j].cursive_chain() > 0)
	pos[j].x_offset += pos[j + pos[j].cursive_chain()].x_offset;
    }
  }


  /* Handle attachments */
  for (i = 0; i < len; i++)
B
Behdad Esfahbod 已提交
1530
    if (pos[i].attach_lookback())
B
Behdad Esfahbod 已提交
1531
    {
B
Behdad Esfahbod 已提交
1532
      unsigned int back = i - pos[i].attach_lookback();
B
Behdad Esfahbod 已提交
1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548
      pos[i].x_offset += pos[back].x_offset;
      pos[i].y_offset += pos[back].y_offset;

      if (HB_DIRECTION_IS_BACKWARD (buffer->props.direction))
	for (j = back + 1; j < i + 1; j++) {
	  pos[i].x_offset += pos[j].x_advance;
	  pos[i].y_offset += pos[j].y_advance;
	}
      else
	for (j = back; j < i; j++) {
	  pos[i].x_offset -= pos[j].x_advance;
	  pos[i].y_offset -= pos[j].y_advance;
	}
    }
}

B
Behdad Esfahbod 已提交
1549 1550 1551

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

B
Behdad Esfahbod 已提交
1552
inline bool ExtensionPos::apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1553
{
1554
  TRACE_APPLY ();
B
Behdad Esfahbod 已提交
1555
  return get_subtable ().apply (c, get_type ());
B
Behdad Esfahbod 已提交
1556 1557
}

B
Behdad Esfahbod 已提交
1558
inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
B
Behdad Esfahbod 已提交
1559
{
1560
  TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
1561
  if (unlikely (!Extension::sanitize (c))) return false;
B
Behdad Esfahbod 已提交
1562
  unsigned int offset = get_offset ();
1563
  if (unlikely (!offset)) return true;
B
Behdad Esfahbod 已提交
1564
  return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
B
Behdad Esfahbod 已提交
1565 1566
}

B
Behdad Esfahbod 已提交
1567
static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1568
{
B
Behdad Esfahbod 已提交
1569
  const GPOS &gpos = *(c->layout->face->ot_layout->gpos);
B
Behdad Esfahbod 已提交
1570 1571
  const PosLookup &l = gpos.get_lookup (lookup_index);

B
Behdad Esfahbod 已提交
1572
  if (unlikely (c->nesting_level_left == 0))
B
Behdad Esfahbod 已提交
1573 1574
    return false;

B
Behdad Esfahbod 已提交
1575
  if (unlikely (c->context_length < 1))
B
Behdad Esfahbod 已提交
1576 1577
    return false;

B
Behdad Esfahbod 已提交
1578
  return l.apply_once (c->layout, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
B
Behdad Esfahbod 已提交
1579 1580 1581
}


B
Behdad Esfahbod 已提交
1582 1583 1584 1585
#undef attach_lookback
#undef cursive_chain


B
Behdad Esfahbod 已提交
1586 1587
HB_END_DECLS

1588
#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */