hb-ot-layout-gpos-private.hh 37.1 KB
Newer Older
B
Behdad Esfahbod 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*
 * Copyright (C) 2007,2008,2009  Red Hat, Inc.
 *
 *  This is part of HarfBuzz, an OpenType Layout engine library.
 *
 * 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
 */

27 28
#ifndef HB_OT_LAYOUT_GPOS_PRIVATE_HH
#define HB_OT_LAYOUT_GPOS_PRIVATE_HH
B
Behdad Esfahbod 已提交
29

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

B
Behdad Esfahbod 已提交
32
#define HB_OT_LAYOUT_GPOS_NO_LAST ((unsigned int) -1)
B
Behdad Esfahbod 已提交
33 34 35 36 37 38

/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */

typedef SHORT Value;
typedef Value ValueRecord[];

B
Behdad Esfahbod 已提交
39 40 41 42
struct ValueFormat : USHORT
{
  enum
  {
43 44 45 46 47 48 49 50
    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 */
51
    ignored	= 0x0F00,	/* Was used in TrueType Open for MM fonts */
52 53 54
    reserved	= 0xF000,	/* For future use */
  };

B
Behdad Esfahbod 已提交
55
  inline unsigned int get_len () const
B
Behdad Esfahbod 已提交
56
  { return _hb_popcount32 ((unsigned int) *this); }
B
Behdad Esfahbod 已提交
57

58
  const void apply_value (hb_ot_layout_context_t *context,
B
Behdad Esfahbod 已提交
59 60
			  const char          *base,
			  const Value         *values,
61
			  hb_internal_glyph_position_t *glyph_pos) const
62 63 64 65 66 67 68
  {
    unsigned int x_ppem, y_ppem;
    hb_16dot16_t x_scale, y_scale;
    unsigned int pixel_value;
    unsigned int format = *this;

    if (!format)
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
      return;

    /* All fields are options.  Only those available advance the value
     * pointer. */
#if 0
struct ValueRecord {
  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
99

100 101
    x_scale = context->font->x_scale;
    y_scale = context->font->y_scale;
102 103
    /* design units -> fractional pixel */
    if (format & xPlacement)
B
Behdad Esfahbod 已提交
104
      glyph_pos->x_pos += x_scale * *(SHORT*)values++ / 0x10000;
105
    if (format & yPlacement)
B
Behdad Esfahbod 已提交
106
      glyph_pos->y_pos += y_scale * *(SHORT*)values++ / 0x10000;
107
    if (format & xAdvance)
B
Behdad Esfahbod 已提交
108
      glyph_pos->x_advance += x_scale * *(SHORT*)values++ / 0x10000;
109
    if (format & yAdvance)
B
Behdad Esfahbod 已提交
110
      glyph_pos->y_advance += y_scale * *(SHORT*)values++ / 0x10000;
111

112 113
    x_ppem = context->font->x_ppem;
    y_ppem = context->font->y_ppem;
114 115 116
    /* pixel -> fractional pixel */
    if (format & xPlaDevice) {
      if (x_ppem)
117
	glyph_pos->x_pos += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
118 119 120 121 122
      else
        values++;
    }
    if (format & yPlaDevice) {
      if (y_ppem)
123
	glyph_pos->y_pos += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
124 125 126 127 128
      else
        values++;
    }
    if (format & xAdvDevice) {
      if (x_ppem)
129
	glyph_pos->x_advance += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
130 131 132 133 134
      else
        values++;
    }
    if (format & yAdvDevice) {
      if (y_ppem)
135
	glyph_pos->y_advance += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
136 137
      else
        values++;
138 139
    }
  }
B
Behdad Esfahbod 已提交
140
};
141
ASSERT_SIZE (ValueFormat, 2);
B
Behdad Esfahbod 已提交
142 143


B
Behdad Esfahbod 已提交
144 145
struct AnchorFormat1
{
B
Behdad Esfahbod 已提交
146 147 148
  friend struct Anchor;

  private:
149
  inline void get_anchor (hb_ot_layout_context_t *context, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
150 151
			  hb_position_t *x, hb_position_t *y) const
  {
152 153
      *x = context->font->x_scale * xCoordinate / 0x10000;
      *y = context->font->y_scale * yCoordinate / 0x10000;
B
Behdad Esfahbod 已提交
154 155 156 157 158 159 160 161 162
  }

  private:
  USHORT	format;			/* Format identifier--format = 1 */
  SHORT		xCoordinate;		/* Horizontal value--in design units */
  SHORT		yCoordinate;		/* Vertical value--in design units */
};
ASSERT_SIZE (AnchorFormat1, 6);

B
Behdad Esfahbod 已提交
163 164
struct AnchorFormat2
{
B
Behdad Esfahbod 已提交
165 166 167
  friend struct Anchor;

  private:
168
  inline void get_anchor (hb_ot_layout_context_t *context, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
169 170
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
171
      /* TODO Contour */
172 173
      *x = context->font->x_scale * xCoordinate / 0x10000;
      *y = context->font->y_scale * yCoordinate / 0x10000;
B
Behdad Esfahbod 已提交
174 175 176 177 178 179 180 181 182 183
  }

  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 */
};
ASSERT_SIZE (AnchorFormat2, 8);

B
Behdad Esfahbod 已提交
184 185
struct AnchorFormat3
{
B
Behdad Esfahbod 已提交
186 187 188
  friend struct Anchor;

  private:
189
  inline void get_anchor (hb_ot_layout_context_t *context, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
190 191
			  hb_position_t *x, hb_position_t *y) const
  {
192 193
      *x = context->font->x_scale * xCoordinate / 0x10000;
      *y = context->font->y_scale * yCoordinate / 0x10000;
194

195 196 197 198
      if (context->font->x_ppem)
	*x += (this+xDeviceTable).get_delta (context->font->x_ppem) << 6;
      if (context->font->y_ppem)
	*y += (this+yDeviceTable).get_delta (context->font->y_ppem) << 6;
B
Behdad Esfahbod 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
  }

  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) */
};
ASSERT_SIZE (AnchorFormat3, 10);

B
Behdad Esfahbod 已提交
216 217
struct Anchor
{
218
  inline void get_anchor (hb_ot_layout_context_t *context, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
219 220
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
221 222
    *x = *y = 0;
    switch (u.format) {
223 224 225 226
    case 1: u.format1->get_anchor (context, glyph_id, x, y); return;
    case 2: u.format2->get_anchor (context, glyph_id, x, y); return;
    case 3: u.format3->get_anchor (context, glyph_id, x, y); return;
    default:						     return;
B
Behdad Esfahbod 已提交
227 228 229 230 231 232 233 234 235 236 237 238 239 240
    }
  }

  private:
  union {
  USHORT		format;		/* Format identifier */
  AnchorFormat1		format1[];
  AnchorFormat2		format2[];
  AnchorFormat3		format3[];
  } u;
};
ASSERT_SIZE (Anchor, 2);


B
Behdad Esfahbod 已提交
241 242
struct MarkRecord
{
243
  friend struct MarkArray;
B
Behdad Esfahbod 已提交
244 245 246 247 248 249 250 251 252

  private:
  USHORT	klass;			/* Class defined for this mark */
  OffsetTo<Anchor>
		markAnchor;		/* Offset to Anchor table--from
					 * beginning of MarkArray table */
};
ASSERT_SIZE (MarkRecord, 4);

B
Behdad Esfahbod 已提交
253 254
struct MarkArray
{
B
Behdad Esfahbod 已提交
255 256
  inline unsigned int get_class (unsigned int index) const { return markRecord[index].klass; }
  inline const Anchor& get_anchor (unsigned int index) const { return this+markRecord[index].markAnchor; }
B
Behdad Esfahbod 已提交
257 258 259 260 261 262 263 264 265 266

  private:
  ArrayOf<MarkRecord>
		markRecord;	/* Array of MarkRecords--in Coverage order */
};
ASSERT_SIZE (MarkArray, 2);


/* Lookups */

B
Behdad Esfahbod 已提交
267 268
struct SinglePosFormat1
{
B
Behdad Esfahbod 已提交
269 270 271
  friend struct SinglePos;

  private:
B
Behdad Esfahbod 已提交
272 273
  inline bool apply (APPLY_ARG_DEF) const
  {
274 275 276 277
    unsigned int index = (this+coverage) (IN_CURGLYPH ());
    if (HB_LIKELY (index == NOT_COVERED))
      return false;

278
    valueFormat.apply_value (context, CONST_CHARP(this), values, CURPOSITION ());
279 280

    buffer->in_pos++;
281
    return true;
B
Behdad Esfahbod 已提交
282 283 284 285 286 287 288
  }

  private:
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
289
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
290 291 292 293 294 295 296
					 * ValueRecord */
  ValueRecord	values;			/* Defines positioning
					 * value(s)--applied to all glyphs in
					 * the Coverage table */
};
ASSERT_SIZE (SinglePosFormat1, 6);

B
Behdad Esfahbod 已提交
297 298
struct SinglePosFormat2
{
B
Behdad Esfahbod 已提交
299 300 301
  friend struct SinglePos;

  private:
B
Behdad Esfahbod 已提交
302 303
  inline bool apply (APPLY_ARG_DEF) const
  {
304 305 306 307 308 309 310
    unsigned int index = (this+coverage) (IN_CURGLYPH ());
    if (HB_LIKELY (index == NOT_COVERED))
      return false;

    if (HB_LIKELY (index >= valueCount))
      return false;

311
    valueFormat.apply_value (context, CONST_CHARP(this),
312 313
			     values + index * valueFormat.get_len (),
			     CURPOSITION ());
314 315

    buffer->in_pos++;
316
    return true;
B
Behdad Esfahbod 已提交
317 318 319 320 321 322 323
  }

  private:
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
324
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
325 326 327 328 329 330 331
					 * ValueRecord */
  USHORT	valueCount;		/* Number of ValueRecords */
  ValueRecord	values;			/* Array of ValueRecords--positioning
					 * values applied to glyphs */
};
ASSERT_SIZE (SinglePosFormat2, 8);

B
Behdad Esfahbod 已提交
332 333
struct SinglePos
{
B
Behdad Esfahbod 已提交
334 335 336
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
337 338
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
339
    switch (u.format) {
340 341
    case 1: return u.format1->apply (APPLY_ARG);
    case 2: return u.format2->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
342 343 344 345 346 347 348 349 350 351 352 353 354 355
    default:return false;
    }
  }

  private:
  union {
  USHORT		format;		/* Format identifier */
  SinglePosFormat1	format1[];
  SinglePosFormat2	format2[];
  } u;
};
ASSERT_SIZE (SinglePos, 2);


B
Behdad Esfahbod 已提交
356 357
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
358
  friend struct PairPosFormat1;
B
Behdad Esfahbod 已提交
359 360 361 362 363 364 365 366 367 368

  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 */
};
ASSERT_SIZE (PairValueRecord, 2);

B
Behdad Esfahbod 已提交
369 370
struct PairSet
{
B
Behdad Esfahbod 已提交
371 372 373 374 375 376 377 378
  friend struct PairPosFormat1;

  private:
  USHORT	len;			/* Number of PairValueRecords */
  PairValueRecord
		array[];		/* Array of PairValueRecords--ordered
					 * by GlyphID of the second glyph */
};
B
Behdad Esfahbod 已提交
379 380
ASSERT_SIZE (PairSet, 2);

B
Behdad Esfahbod 已提交
381 382
struct PairPosFormat1
{
B
Behdad Esfahbod 已提交
383 384 385
  friend struct PairPos;

  private:
B
Behdad Esfahbod 已提交
386 387 388 389 390 391 392 393 394 395 396
  inline bool apply (APPLY_ARG_DEF) const
  {
    unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
    if (HB_UNLIKELY (buffer->in_pos + 2 > end))
      return false;

    unsigned int index = (this+coverage) (IN_CURGLYPH ());
    if (HB_LIKELY (index == NOT_COVERED))
      return false;

    unsigned int j = buffer->in_pos + 1;
397
    while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), lookup_flag, NULL))
B
Behdad Esfahbod 已提交
398
    {
B
Behdad Esfahbod 已提交
399 400 401 402 403 404 405
      if (HB_UNLIKELY (j == end))
	return false;
      j++;
    }

    const PairSet &pair_set = this+pairSet[index];

B
Behdad Esfahbod 已提交
406 407
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
B
Behdad Esfahbod 已提交
408 409 410 411
    unsigned int record_len = 1 + len1 + len2;

    unsigned int count = pair_set.len;
    const PairValueRecord *record = pair_set.array;
B
Behdad Esfahbod 已提交
412 413 414 415
    for (unsigned int i = 0; i < count; i++)
    {
      if (IN_GLYPH (j) == record->secondGlyph)
      {
416 417
	valueFormat1.apply_value (context, CONST_CHARP(this), record->values, CURPOSITION ());
	valueFormat2.apply_value (context, CONST_CHARP(this), record->values + len1, POSITION (j));
B
Behdad Esfahbod 已提交
418 419 420 421 422 423 424 425
	if (len2)
	  j++;
	buffer->in_pos = j;
	return true;
      }
      record += record_len;
    }

B
Behdad Esfahbod 已提交
426 427 428 429 430 431 432 433
    return false;
  }

  private:
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
434
  ValueFormat	valueFormat1;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
435 436
					 * ValueRecord1--for the first glyph
					 * in the pair--may be zero (0) */
437
  ValueFormat	valueFormat2;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
438 439 440 441 442 443 444 445
					 * ValueRecord2--for the second glyph
					 * in the pair--may be zero (0) */
  OffsetArrayOf<PairSet>
		pairSet;		/* Array of PairSet tables
					 * ordered by Coverage Index */
};
ASSERT_SIZE (PairPosFormat1, 10);

B
Behdad Esfahbod 已提交
446 447
struct PairPosFormat2
{
B
Behdad Esfahbod 已提交
448 449 450
  friend struct PairPos;

  private:
B
Behdad Esfahbod 已提交
451 452 453 454 455 456 457 458 459 460 461
  inline bool apply (APPLY_ARG_DEF) const
  {
    unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
    if (HB_UNLIKELY (buffer->in_pos + 2 > end))
      return false;

    unsigned int index = (this+coverage) (IN_CURGLYPH ());
    if (HB_LIKELY (index == NOT_COVERED))
      return false;

    unsigned int j = buffer->in_pos + 1;
462
    while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), lookup_flag, NULL))
B
Behdad Esfahbod 已提交
463
    {
B
Behdad Esfahbod 已提交
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
      if (HB_UNLIKELY (j == end))
	return false;
      j++;
    }

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

    unsigned int klass1 = (this+classDef1) (IN_CURGLYPH ());
    unsigned int klass2 = (this+classDef2) (IN_GLYPH (j));
    if (HB_UNLIKELY (klass1 >= class1Count || klass2 >= class2Count))
      return false;

    const Value *v = values + record_len * (klass1 * class2Count + klass2);
479 480
    valueFormat1.apply_value (context, CONST_CHARP(this), v, CURPOSITION ());
    valueFormat2.apply_value (context, CONST_CHARP(this), v + len1, POSITION (j));
B
Behdad Esfahbod 已提交
481 482 483 484 485 486

    if (len2)
      j++;
    buffer->in_pos = j;

    return true;
B
Behdad Esfahbod 已提交
487 488
  }

B
Behdad Esfahbod 已提交
489

B
Behdad Esfahbod 已提交
490 491 492 493 494
  private:
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
495
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
496 497
					 * first glyph of the pair--may be zero
					 * (0) */
498
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518
					 * 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 */
};
ASSERT_SIZE (PairPosFormat2, 16);

B
Behdad Esfahbod 已提交
519 520
struct PairPos
{
B
Behdad Esfahbod 已提交
521 522 523
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
524 525
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
526
    switch (u.format) {
527 528
    case 1: return u.format1->apply (APPLY_ARG);
    case 2: return u.format2->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
529 530 531 532 533 534 535 536 537 538 539 540 541 542
    default:return false;
    }
  }

  private:
  union {
  USHORT		format;		/* Format identifier */
  PairPosFormat1	format1[];
  PairPosFormat2	format2[];
  } u;
};
ASSERT_SIZE (PairPos, 2);


B
Behdad Esfahbod 已提交
543 544
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
545 546 547 548 549 550 551 552 553 554 555
  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 */
};
ASSERT_SIZE (EntryExitRecord, 4);

B
Behdad Esfahbod 已提交
556 557
struct CursivePosFormat1
{
B
Behdad Esfahbod 已提交
558 559 560
  friend struct CursivePos;

  private:
B
Behdad Esfahbod 已提交
561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
  inline bool apply (APPLY_ARG_DEF) const
  {
    /* Now comes the messiest part of the whole OpenType
       specification.  At first glance, cursive connections seem easy
       to understand, but there are pitfalls!  The reason is that
       the specs don't mention how to compute the advance values
       resp. glyph offsets.  I was told it would be an omission, to
       be fixed in the next OpenType version...  Again many thanks to
       Andrei Burago <andreib@microsoft.com> for clarifications.

       Consider the following example:

			|  xadv1    |
			 +---------+
			 |         |
		   +-----+--+ 1    |
		   |     | .|      |
		   |    0+--+------+
		   |   2    |
		   |        |
		  0+--------+
		  |  xadv2   |

	 glyph1: advance width = 12
		 anchor point = (3,1)

	 glyph2: advance width = 11
		 anchor point = (9,4)

	 LSB is 1 for both glyphs (so the boxes drawn above are glyph
	 bboxes).  Writing direction is R2L; `0' denotes the glyph's
	 coordinate origin.

       Now the surprising part: The advance width of the *left* glyph
       (resp. of the *bottom* glyph) will be modified, no matter
       whether the writing direction is L2R or R2L (resp. T2B or
       B2T)!  This assymetry is caused by the fact that the glyph's
       coordinate origin is always the lower left corner for all
       writing directions.

       Continuing the above example, we can compute the new
       (horizontal) advance width of glyph2 as

	 9 - 3 = 6  ,

       and the new vertical offset of glyph2 as

	 1 - 4 = -3  .


       Vertical writing direction is far more complicated:

       a) Assuming that we recompute the advance height of the lower glyph:

				    --
			 +---------+
		--       |         |
		   +-----+--+ 1    | yadv1
		   |     | .|      |
	     yadv2 |    0+--+------+        -- BSB1  --
		   |   2    |       --      --        y_offset
		   |        |
     BSB2 --      0+--------+                        --
	  --    --

	 glyph1: advance height = 6
		 anchor point = (3,1)

	 glyph2: advance height = 7
		 anchor point = (9,4)

	 TSB is 1 for both glyphs; writing direction is T2B.


	   BSB1     = yadv1 - (TSB1 + ymax1)
	   BSB2     = yadv2 - (TSB2 + ymax2)
	   y_offset = y2 - y1

	 vertical advance width of glyph2
	   = y_offset + BSB2 - BSB1
	   = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
	   = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
	   = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1


       b) Assuming that we recompute the advance height of the upper glyph:

				    --      --
			 +---------+        -- TSB1
	  --    --       |         |
     TSB2 --       +-----+--+ 1    | yadv1   ymax1
		   |     | .|      |
	     yadv2 |    0+--+------+        --       --
      ymax2        |   2    |       --                y_offset
		   |        |
	  --      0+--------+                        --
		--

	 glyph1: advance height = 6
		 anchor point = (3,1)

	 glyph2: advance height = 7
		 anchor point = (9,4)

	 TSB is 1 for both glyphs; writing direction is T2B.

	 y_offset = y2 - y1

	 vertical advance width of glyph2
	   = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
	   = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2


       Comparing a) with b) shows that b) is easier to compute.  I'll wait
       for a reply from Andrei to see what should really be implemented...

       Since horizontal advance widths or vertical advance heights
       can be used alone but not together, no ambiguity occurs.        */

680
    struct hb_ot_layout_context_t::info_t::gpos_t *gpi = &context->info.gpos;
B
Behdad Esfahbod 已提交
681
    hb_codepoint_t last_pos = gpi->last;
B
Behdad Esfahbod 已提交
682
    gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
B
Behdad Esfahbod 已提交
683 684 685 686 687 688 689 690 691

    /* We don't handle mark glyphs here. */
    if (property == HB_OT_LAYOUT_GLYPH_CLASS_MARK)
      return false;

    unsigned int index = (this+coverage) (IN_CURGLYPH ());
    if (HB_LIKELY (index == NOT_COVERED))
      return false;

B
Behdad Esfahbod 已提交
692 693
    const EntryExitRecord &record = entryExitRecord[index];

B
Behdad Esfahbod 已提交
694
    if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
B
Behdad Esfahbod 已提交
695 696
      goto end;

B
Behdad Esfahbod 已提交
697
    hb_position_t entry_x, entry_y;
698
    (this+record.entryAnchor).get_anchor (context, IN_CURGLYPH (), &entry_x, &entry_y);
B
Behdad Esfahbod 已提交
699

B
Behdad Esfahbod 已提交
700 701
    /* TODO vertical */

B
Behdad Esfahbod 已提交
702
    if (buffer->direction == HB_DIRECTION_RTL)
B
Behdad Esfahbod 已提交
703 704 705 706 707 708
    {
      POSITION (buffer->in_pos)->x_advance   = entry_x - gpi->anchor_x;
      POSITION (buffer->in_pos)->new_advance = TRUE;
    }
    else
    {
B
Behdad Esfahbod 已提交
709 710
      POSITION (last_pos)->x_advance   = gpi->anchor_x - entry_x;
      POSITION (last_pos)->new_advance = TRUE;
B
Behdad Esfahbod 已提交
711 712 713 714
    }

    if  (lookup_flag & LookupFlag::RightToLeft)
    {
B
Behdad Esfahbod 已提交
715 716
      POSITION (last_pos)->cursive_chain = last_pos - buffer->in_pos;
      POSITION (last_pos)->y_pos = entry_y - gpi->anchor_y;
B
Behdad Esfahbod 已提交
717 718 719
    }
    else
    {
B
Behdad Esfahbod 已提交
720
      POSITION (buffer->in_pos)->cursive_chain = buffer->in_pos - last_pos;
B
Behdad Esfahbod 已提交
721 722 723 724 725
      POSITION (buffer->in_pos)->y_pos = gpi->anchor_y - entry_y;
    }

  end:
    if (record.exitAnchor)
B
Behdad Esfahbod 已提交
726 727
    {
      gpi->last = buffer->in_pos;
728
      (this+record.exitAnchor).get_anchor (context, IN_CURGLYPH (), &gpi->anchor_x, &gpi->anchor_y);
B
Behdad Esfahbod 已提交
729
    }
B
Behdad Esfahbod 已提交
730 731 732

    buffer->in_pos++;
    return true;
B
Behdad Esfahbod 已提交
733 734 735 736 737 738 739 740 741 742 743 744 745
  }

  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 */
};
ASSERT_SIZE (CursivePosFormat1, 6);

B
Behdad Esfahbod 已提交
746 747
struct CursivePos
{
B
Behdad Esfahbod 已提交
748 749 750
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
751 752
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
753
    switch (u.format) {
754
    case 1: return u.format1->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
755 756 757 758 759 760 761 762 763 764 765 766 767
    default:return false;
    }
  }

  private:
  union {
  USHORT		format;		/* Format identifier */
  CursivePosFormat1	format1[];
  } u;
};
ASSERT_SIZE (CursivePos, 2);


B
Behdad Esfahbod 已提交
768 769
struct BaseArray
{
B
Behdad Esfahbod 已提交
770
  friend struct MarkBasePosFormat1;
B
Behdad Esfahbod 已提交
771 772

  private:
B
Behdad Esfahbod 已提交
773 774 775 776 777 778 779
  USHORT	len;			/* Number of rows */
  OffsetTo<Anchor>
		matrix[];		/* Matrix of offsets to Anchor tables--
					 * from beginning of BaseArray table--
					 * base-major--in order of
					 * BaseCoverage Index--, mark-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
780 781 782
};
ASSERT_SIZE (BaseArray, 2);

B
Behdad Esfahbod 已提交
783 784
struct MarkBasePosFormat1
{
B
Behdad Esfahbod 已提交
785 786 787
  friend struct MarkBasePos;

  private:
B
Behdad Esfahbod 已提交
788 789
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
790 791 792 793 794 795 796
    unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
    if (HB_LIKELY (mark_index == NOT_COVERED))
      return false;

    /* now we search backwards for a non-mark glyph */
    unsigned int count = buffer->in_pos;
    unsigned int i = 1, j = count - 1;
797
    while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property))
B
Behdad Esfahbod 已提交
798
    {
B
Behdad Esfahbod 已提交
799 800
      if (HB_UNLIKELY (i == count))
	return false;
B
Behdad Esfahbod 已提交
801 802
      i++, j--;
    }
B
Behdad Esfahbod 已提交
803
#if 0
B
Behdad Esfahbod 已提交
804 805
    /* The following assertion is too strong. */
    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
B
Behdad Esfahbod 已提交
806
      return false;
B
Behdad Esfahbod 已提交
807
#endif
B
Behdad Esfahbod 已提交
808 809

    unsigned int base_index = (this+baseCoverage) (IN_GLYPH (j));
B
Behdad Esfahbod 已提交
810
    if (base_index == NOT_COVERED)
B
Behdad Esfahbod 已提交
811 812 813 814 815 816 817 818 819 820 821 822 823
      return false;

    const MarkArray& mark_array = this+markArray;
    const BaseArray& base_array = this+baseArray;

    unsigned int mark_class = mark_array.get_class (mark_index);
    const Anchor& mark_anchor = mark_array.get_anchor (mark_index);

    if (HB_UNLIKELY (mark_class >= classCount || base_index >= base_array.len))
      return false;

    hb_position_t mark_x, mark_y, base_x, base_y;

824
    mark_anchor.get_anchor (context, IN_CURGLYPH (), &mark_x, &mark_y);
B
Behdad Esfahbod 已提交
825
    unsigned int index = base_index * classCount + mark_class;
826
    (&base_array+base_array.matrix[index]).get_anchor (context, IN_GLYPH (j), &base_x, &base_y);
B
Behdad Esfahbod 已提交
827

828
    hb_internal_glyph_position_t *o = POSITION (buffer->in_pos);
B
Behdad Esfahbod 已提交
829 830 831 832 833 834 835 836
    o->x_pos     = base_x - mark_x;
    o->y_pos     = base_y - mark_y;
    o->x_advance = 0;
    o->y_advance = 0;
    o->back      = i;

    buffer->in_pos++;
    return true;
B
Behdad Esfahbod 已提交
837 838 839 840
  }

  private:
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
841 842
  OffsetTo<Coverage>
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
843
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
844 845
  OffsetTo<Coverage>
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
846 847
					 * beginning of MarkBasePos subtable */
  USHORT	classCount;		/* Number of classes defined for marks */
B
Behdad Esfahbod 已提交
848 849
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
850
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
851 852
  OffsetTo<BaseArray>
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
853 854 855 856
					 * beginning of MarkBasePos subtable */
};
ASSERT_SIZE (MarkBasePosFormat1, 12);

B
Behdad Esfahbod 已提交
857 858
struct MarkBasePos
{
B
Behdad Esfahbod 已提交
859 860 861
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
862 863
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
864
    switch (u.format) {
865
    case 1: return u.format1->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
866 867 868 869 870 871 872 873 874 875 876 877 878
    default:return false;
    }
  }

  private:
  union {
  USHORT		format;		/* Format identifier */
  MarkBasePosFormat1	format1[];
  } u;
};
ASSERT_SIZE (MarkBasePos, 2);


B
Behdad Esfahbod 已提交
879 880
struct LigatureAttach
{
B
Behdad Esfahbod 已提交
881
  friend struct MarkLigPosFormat1;
B
Behdad Esfahbod 已提交
882 883

  private:
B
Behdad Esfahbod 已提交
884 885 886 887 888 889 890 891
  USHORT	len;			/* Number of ComponentRecords in this
					 * ligature, ie. number of rows */
  OffsetTo<Anchor>
		matrix[];		/* Matrix of offsets to Anchor tables--
					 * from beginning of LigatureAttach table--
					 * component-major--in order of
					 * writing direction--, mark-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
892 893 894
};
ASSERT_SIZE (LigatureAttach, 2);

B
Behdad Esfahbod 已提交
895 896
typedef OffsetArrayOf<LigatureAttach> LigatureArray;
					/* Array of LigatureAttach
B
Behdad Esfahbod 已提交
897 898 899 900
					 * tables ordered by
					 * LigatureCoverage Index */
ASSERT_SIZE (LigatureArray, 2);

B
Behdad Esfahbod 已提交
901 902
struct MarkLigPosFormat1
{
B
Behdad Esfahbod 已提交
903 904 905
  friend struct MarkLigPos;

  private:
B
Behdad Esfahbod 已提交
906 907
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
908 909 910 911 912 913 914
    unsigned int mark_index = (this+markCoverage) (IN_CURGLYPH ());
    if (HB_LIKELY (mark_index == NOT_COVERED))
      return false;

    /* now we search backwards for a non-mark glyph */
    unsigned int count = buffer->in_pos;
    unsigned int i = 1, j = count - 1;
915
    while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), LookupFlag::IgnoreMarks, &property))
B
Behdad Esfahbod 已提交
916
    {
B
Behdad Esfahbod 已提交
917 918
      if (HB_UNLIKELY (i == count))
	return false;
B
Behdad Esfahbod 已提交
919 920 921
      i++, j--;
    }
#if 0
B
Behdad Esfahbod 已提交
922 923
    /* The following assertion is too strong. */
    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
B
Behdad Esfahbod 已提交
924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
      return false;
#endif

    unsigned int lig_index = (this+ligatureCoverage) (IN_GLYPH (j));
    if (lig_index == NOT_COVERED)
      return false;

    const MarkArray& mark_array = this+markArray;
    const LigatureArray& lig_array = this+ligatureArray;

    unsigned int mark_class = mark_array.get_class (mark_index);
    const Anchor& mark_anchor = mark_array.get_anchor (mark_index);

    if (HB_UNLIKELY (mark_class >= classCount || lig_index >= lig_array.len))
      return false;

    const LigatureAttach& lig_attach = &lig_array+lig_array[lig_index];
    count = lig_attach.len;
    if (HB_UNLIKELY (!count))
      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. */
    if (IN_LIGID (j) == IN_LIGID (buffer->in_pos))
    {
      comp_index = IN_COMPONENT (buffer->in_pos);
      if (comp_index >= count)
	comp_index = count - 1;
    }
    else
      comp_index = count - 1;

    hb_position_t mark_x, mark_y, lig_x, lig_y;

961
    mark_anchor.get_anchor (context, IN_CURGLYPH (), &mark_x, &mark_y);
B
Behdad Esfahbod 已提交
962
    unsigned int index = comp_index * classCount + mark_class;
963
    (&lig_attach+lig_attach.matrix[index]).get_anchor (context, IN_GLYPH (j), &lig_x, &lig_y);
B
Behdad Esfahbod 已提交
964

965
    hb_internal_glyph_position_t *o = POSITION (buffer->in_pos);
B
Behdad Esfahbod 已提交
966 967 968 969 970 971 972 973
    o->x_pos     = lig_x - mark_x;
    o->y_pos     = lig_y - mark_y;
    o->x_advance = 0;
    o->y_advance = 0;
    o->back      = i;

    buffer->in_pos++;
    return true;
B
Behdad Esfahbod 已提交
974 975 976 977
  }

  private:
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
978 979
  OffsetTo<Coverage>
		markCoverage;		/* Offset to Mark Coverage table--from
B
Behdad Esfahbod 已提交
980
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
981 982
  OffsetTo<Coverage>
		ligatureCoverage;	/* Offset to Ligature Coverage
B
Behdad Esfahbod 已提交
983 984 985
					 * table--from beginning of MarkLigPos
					 * subtable */
  USHORT	classCount;		/* Number of defined mark classes */
B
Behdad Esfahbod 已提交
986 987
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
988
					 * beginning of MarkLigPos subtable */
B
Behdad Esfahbod 已提交
989 990
  OffsetTo<LigatureArray>
		ligatureArray;		/* Offset to LigatureArray table--from
B
Behdad Esfahbod 已提交
991 992 993 994
					 * beginning of MarkLigPos subtable */
};
ASSERT_SIZE (MarkLigPosFormat1, 12);

B
Behdad Esfahbod 已提交
995 996
struct MarkLigPos
{
B
Behdad Esfahbod 已提交
997 998 999
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1000 1001
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
1002
    switch (u.format) {
1003
    case 1: return u.format1->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
    default:return false;
    }
  }

  private:
  union {
  USHORT		format;		/* Format identifier */
  MarkLigPosFormat1	format1[];
  } u;
};
ASSERT_SIZE (MarkLigPos, 2);


B
Behdad Esfahbod 已提交
1017 1018
struct Mark2Array
{
B
Behdad Esfahbod 已提交
1019
  friend struct MarkMarkPosFormat1;
B
Behdad Esfahbod 已提交
1020 1021

  private:
B
Behdad Esfahbod 已提交
1022 1023 1024 1025 1026 1027 1028
  USHORT	len;			/* Number of rows */
  OffsetTo<Anchor>
		matrix[];		/* Matrix of offsets to Anchor tables--
					 * from beginning of Mark2Array table--
					 * mark2-major--in order of
					 * Mark2Coverage Index--, mark1-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1029 1030 1031
};
ASSERT_SIZE (Mark2Array, 2);

B
Behdad Esfahbod 已提交
1032 1033
struct MarkMarkPosFormat1
{
B
Behdad Esfahbod 已提交
1034 1035 1036
  friend struct MarkMarkPos;

  private:
B
Behdad Esfahbod 已提交
1037 1038
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
1039 1040 1041 1042 1043 1044 1045
    unsigned int mark1_index = (this+mark1Coverage) (IN_CURGLYPH ());
    if (HB_LIKELY (mark1_index == NOT_COVERED))
      return false;

    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
    unsigned int count = buffer->in_pos;
    unsigned int i = 1, j = count - 1;
1046
    while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), lookup_flag, &property))
B
Behdad Esfahbod 已提交
1047
    {
B
Behdad Esfahbod 已提交
1048 1049
      if (HB_UNLIKELY (i == count))
	return false;
B
Behdad Esfahbod 已提交
1050 1051
      i++, j--;
    }
B
Behdad Esfahbod 已提交
1052 1053 1054 1055 1056 1057 1058
    if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
      return false;

    /* Two marks match only if they belong to the same base, or same component
     * of the same ligature. */
    if (IN_LIGID (j) != IN_LIGID (buffer->in_pos) ||
        IN_COMPONENT (j) != IN_COMPONENT (buffer->in_pos))
B
Behdad Esfahbod 已提交
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
      return false;

    unsigned int mark2_index = (this+mark2Coverage) (IN_GLYPH (j));
    if (mark2_index == NOT_COVERED)
      return false;

    const MarkArray& mark1_array = this+mark1Array;
    const Mark2Array& mark2_array = this+mark2Array;

    unsigned int mark1_class = mark1_array.get_class (mark1_index);
    const Anchor& mark1_anchor = mark1_array.get_anchor (mark1_index);

    if (HB_UNLIKELY (mark1_class >= classCount || mark2_index >= mark2_array.len))
      return false;

    hb_position_t mark1_x, mark1_y, mark2_x, mark2_y;

1076
    mark1_anchor.get_anchor (context, IN_CURGLYPH (), &mark1_x, &mark1_y);
B
Behdad Esfahbod 已提交
1077
    unsigned int index = mark2_index * classCount + mark1_class;
1078
    (&mark2_array+mark2_array.matrix[index]).get_anchor (context, IN_GLYPH (j), &mark2_x, &mark2_y);
B
Behdad Esfahbod 已提交
1079

1080
    hb_internal_glyph_position_t *o = POSITION (buffer->in_pos);
B
Behdad Esfahbod 已提交
1081 1082 1083 1084 1085 1086 1087 1088
    o->x_pos     = mark2_x - mark1_x;
    o->y_pos     = mark2_y - mark1_y;
    o->x_advance = 0;
    o->y_advance = 0;
    o->back      = i;

    buffer->in_pos++;
    return true;
B
Behdad Esfahbod 已提交
1089 1090 1091 1092
  }

  private:
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1093 1094
  OffsetTo<Coverage>
		mark1Coverage;		/* Offset to Combining Mark1 Coverage
B
Behdad Esfahbod 已提交
1095 1096
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1097 1098
  OffsetTo<Coverage>
		mark2Coverage;		/* Offset to Combining Mark2 Coverage
B
Behdad Esfahbod 已提交
1099 1100
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
1101 1102 1103 1104 1105 1106 1107
  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 */
B
Behdad Esfahbod 已提交
1108
};
B
Behdad Esfahbod 已提交
1109
ASSERT_SIZE (MarkMarkPosFormat1, 12);
B
Behdad Esfahbod 已提交
1110

B
Behdad Esfahbod 已提交
1111 1112
struct MarkMarkPos
{
B
Behdad Esfahbod 已提交
1113 1114 1115
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1116 1117
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
1118
    switch (u.format) {
1119
    case 1: return u.format1->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132
    default:return false;
    }
  }

  private:
  union {
  USHORT		format;		/* Format identifier */
  MarkMarkPosFormat1	format1[];
  } u;
};
ASSERT_SIZE (MarkMarkPos, 2);


1133
static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1134

B
Behdad Esfahbod 已提交
1135 1136
struct ContextPos : Context
{
1137 1138 1139
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1140
  inline bool apply (APPLY_ARG_DEF) const
B
Behdad Esfahbod 已提交
1141
  { return Context::apply (APPLY_ARG, position_lookup); }
B
Behdad Esfahbod 已提交
1142 1143 1144
};
ASSERT_SIZE (ContextPos, 2);

B
Behdad Esfahbod 已提交
1145 1146
struct ChainContextPos : ChainContext
{
1147 1148 1149
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
1150
  inline bool apply (APPLY_ARG_DEF) const
B
Behdad Esfahbod 已提交
1151
  { return ChainContext::apply (APPLY_ARG, position_lookup); }
B
Behdad Esfahbod 已提交
1152 1153 1154 1155
};
ASSERT_SIZE (ChainContextPos, 2);


1156
struct ExtensionPos : Extension
B
Behdad Esfahbod 已提交
1157
{
B
Behdad Esfahbod 已提交
1158 1159 1160
  friend struct PosLookupSubTable;

  private:
1161
  inline bool apply (APPLY_ARG_DEF) const;
B
Behdad Esfahbod 已提交
1162 1163 1164 1165
};
ASSERT_SIZE (ExtensionPos, 2);


1166

B
Behdad Esfahbod 已提交
1167 1168 1169 1170 1171
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
1172 1173
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
1174 1175
  friend struct PosLookup;

1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
  enum {
    Single		= 1,
    Pair		= 2,
    Cursive		= 3,
    MarkBase		= 4,
    MarkLig		= 5,
    MarkMark		= 6,
    Context		= 7,
    ChainContext	= 8,
    Extension		= 9,
  };

1188
  bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const
B
Behdad Esfahbod 已提交
1189
  {
B
Behdad Esfahbod 已提交
1190
    switch (lookup_type) {
1191 1192 1193 1194 1195 1196 1197 1198 1199
    case Single:		return u.single->apply (APPLY_ARG);
    case Pair:			return u.pair->apply (APPLY_ARG);
    case Cursive:		return u.cursive->apply (APPLY_ARG);
    case MarkBase:		return u.markBase->apply (APPLY_ARG);
    case MarkLig:		return u.markLig->apply (APPLY_ARG);
    case MarkMark:		return u.markMark->apply (APPLY_ARG);
    case Context:		return u.context->apply (APPLY_ARG);
    case ChainContext:		return u.chainContext->apply (APPLY_ARG);
    case Extension:		return u.extension->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
1200 1201 1202 1203 1204 1205
    default:return false;
    }
  }

  private:
  union {
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
  USHORT		format;
  SinglePos		single[];
  PairPos		pair[];
  CursivePos		cursive[];
  MarkBasePos		markBase[];
  MarkLigPos		markLig[];
  MarkMarkPos		markMark[];
  ContextPos		context[];
  ChainContextPos	chainContext[];
  ExtensionPos		extension[];
B
Behdad Esfahbod 已提交
1216 1217 1218 1219 1220
  } u;
};
ASSERT_SIZE (PosLookupSubTable, 2);


B
Behdad Esfahbod 已提交
1221 1222 1223
struct PosLookup : Lookup
{
  inline const PosLookupSubTable& get_subtable (unsigned int i) const
B
Behdad Esfahbod 已提交
1224
  { return (const PosLookupSubTable&) Lookup::get_subtable (i); }
B
Behdad Esfahbod 已提交
1225 1226 1227

  /* Like get_type(), but looks through extension lookups.
   * Never returns Extension */
B
Behdad Esfahbod 已提交
1228 1229
  inline unsigned int get_effective_type (void) const
  {
B
Behdad Esfahbod 已提交
1230 1231
    unsigned int type = get_type ();

1232
    if (HB_UNLIKELY (type == PosLookupSubTable::Extension))
B
Behdad Esfahbod 已提交
1233
    {
B
Behdad Esfahbod 已提交
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
      unsigned int count = get_subtable_count ();
      type = get_subtable(0).u.extension->get_type ();
      /* The spec says all subtables should have the same type.
       * This is specially important if one has a reverse type! */
      for (unsigned int i = 1; i < count; i++)
        if (get_subtable(i).u.extension->get_type () != type)
	  return 0;
    }

    return type;
  }

1246
  inline bool apply_once (hb_ot_layout_context_t *context,
1247 1248 1249
			  hb_buffer_t    *buffer,
			  unsigned int    context_length,
			  unsigned int    nesting_level_left) const
B
Behdad Esfahbod 已提交
1250
  {
B
Behdad Esfahbod 已提交
1251 1252
    unsigned int lookup_type = get_type ();
    unsigned int lookup_flag = get_flag ();
1253 1254
    unsigned int property;

1255
    if (!_hb_ot_layout_check_glyph_property (context->face, IN_CURINFO (), lookup_flag, &property))
1256
      return false;
B
Behdad Esfahbod 已提交
1257 1258

    for (unsigned int i = 0; i < get_subtable_count (); i++)
1259
      if (get_subtable (i).apply (APPLY_ARG, lookup_type))
B
Behdad Esfahbod 已提交
1260 1261 1262 1263 1264
	return true;

    return false;
  }

1265
  bool apply_string (hb_ot_layout_context_t *context,
1266
		     hb_buffer_t    *buffer,
B
Behdad Esfahbod 已提交
1267 1268
		     hb_ot_layout_feature_mask_t mask) const
  {
B
Behdad Esfahbod 已提交
1269 1270 1271 1272 1273
    bool ret = false;

    if (HB_UNLIKELY (!buffer->in_length))
      return false;

1274
    context->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
1275

B
Behdad Esfahbod 已提交
1276
    buffer->in_pos = 0;
B
Behdad Esfahbod 已提交
1277 1278
    while (buffer->in_pos < buffer->in_length)
    {
1279
      bool done;
B
Behdad Esfahbod 已提交
1280 1281
      if (~IN_PROPERTIES (buffer->in_pos) & mask)
      {
1282
	  done = apply_once (context, buffer, NO_CONTEXT, MAX_NESTING_LEVEL);
1283
	  ret |= done;
B
Behdad Esfahbod 已提交
1284 1285 1286
      }
      else
      {
1287 1288 1289
          done = false;
	  /* Contrary to properties defined in GDEF, user-defined properties
	     will always stop a possible cursive positioning.                */
1290
	  context->info.gpos.last = HB_OT_LAYOUT_GPOS_NO_LAST;
1291 1292 1293 1294
      }

      if (!done)
	buffer->in_pos++;
B
Behdad Esfahbod 已提交
1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306
    }

    return ret;
  }
};
ASSERT_SIZE (PosLookup, 6);


/*
 * GPOS
 */

B
Behdad Esfahbod 已提交
1307 1308
struct GPOS : GSUBGPOS
{
B
Behdad Esfahbod 已提交
1309 1310
  static const hb_tag_t Tag		= HB_TAG ('G','P','O','S');

1311
  static inline const GPOS& get_for_data (const char *data)
B
Behdad Esfahbod 已提交
1312
  { return (const GPOS&) GSUBGPOS::get_for_data (data); }
B
Behdad Esfahbod 已提交
1313

B
Behdad Esfahbod 已提交
1314
  inline const PosLookup& get_lookup (unsigned int i) const
B
Behdad Esfahbod 已提交
1315
  { return (const PosLookup&) GSUBGPOS::get_lookup (i); }
B
Behdad Esfahbod 已提交
1316

1317
  inline bool position_lookup (hb_ot_layout_context_t *context,
B
Behdad Esfahbod 已提交
1318 1319
			       hb_buffer_t    *buffer,
			       unsigned int    lookup_index,
B
Behdad Esfahbod 已提交
1320
			       hb_ot_layout_feature_mask_t  mask) const
1321
  { return get_lookup (lookup_index).apply_string (context, buffer, mask); }
B
Behdad Esfahbod 已提交
1322 1323 1324 1325 1326 1327 1328

};
ASSERT_SIZE (GPOS, 10);


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

1329
inline bool ExtensionPos::apply (APPLY_ARG_DEF) const
B
Behdad Esfahbod 已提交
1330
{
B
Behdad Esfahbod 已提交
1331 1332
  unsigned int lookup_type = get_type ();

1333
  if (HB_UNLIKELY (lookup_type == PosLookupSubTable::Extension))
B
Behdad Esfahbod 已提交
1334 1335
    return false;

1336
  return ((PosLookupSubTable&) get_subtable ()).apply (APPLY_ARG, lookup_type);
B
Behdad Esfahbod 已提交
1337 1338
}

B
Behdad Esfahbod 已提交
1339 1340
static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index)
{
1341
  const GPOS &gpos = *(context->face->ot_layout.gpos);
B
Behdad Esfahbod 已提交
1342 1343 1344 1345 1346 1347 1348 1349 1350
  const PosLookup &l = gpos.get_lookup (lookup_index);

  if (HB_UNLIKELY (nesting_level_left == 0))
    return false;
  nesting_level_left--;

  if (HB_UNLIKELY (context_length < 1))
    return false;

1351
  return l.apply_once (context, buffer, context_length, nesting_level_left);
B
Behdad Esfahbod 已提交
1352 1353 1354
}


1355
#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_HH */