hb-ot-layout-gpos-private.h 37.3 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 27 28 29 30 31
/*
 * 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
 */

#ifndef HB_OT_LAYOUT_GPOS_PRIVATE_H
#define HB_OT_LAYOUT_GPOS_PRIVATE_H

#include "hb-ot-layout-gsubgpos-private.h"

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

B
Behdad Esfahbod 已提交
58 59 60 61
  const void apply_value (hb_ot_layout_t      *layout,
			  const char          *base,
			  const Value         *values,
			  hb_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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

    x_scale = layout->gpos_info.x_scale;
    y_scale = layout->gpos_info.y_scale;
    /* design units -> fractional pixel */
    if (format & xPlacement)
      glyph_pos->x_pos += x_scale * *(USHORT*)values++ / 0x10000;
    if (format & yPlacement)
      glyph_pos->y_pos += y_scale * *(USHORT*)values++ / 0x10000;
    if (format & xAdvance)
      glyph_pos->x_advance += x_scale * *(USHORT*)values++ / 0x10000;
    if (format & yAdvance)
      glyph_pos->y_advance += y_scale * *(USHORT*)values++ / 0x10000;

    if (HB_LIKELY (!layout->gpos_info.dvi))
    {
      x_ppem = layout->gpos_info.x_ppem;
      y_ppem = layout->gpos_info.y_ppem;
      /* pixel -> fractional pixel */
      if (format & xPlaDevice)
	glyph_pos->x_pos += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
      if (format & yPlaDevice)
	glyph_pos->y_pos += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
      if (format & xAdvDevice)
	glyph_pos->x_advance += (base+*(OffsetTo<Device>*)values++).get_delta (x_ppem) << 6;
      if (format & yAdvDevice)
	glyph_pos->y_advance += (base+*(OffsetTo<Device>*)values++).get_delta (y_ppem) << 6;
    }
  }
B
Behdad Esfahbod 已提交
127
};
128
ASSERT_SIZE (ValueFormat, 2);
B
Behdad Esfahbod 已提交
129 130


B
Behdad Esfahbod 已提交
131 132
struct AnchorFormat1
{
B
Behdad Esfahbod 已提交
133 134 135 136
  friend struct Anchor;

  private:
  inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
137 138
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
139 140 141 142 143 144 145 146 147 148 149
      *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
      *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
  }

  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 已提交
150 151
struct AnchorFormat2
{
B
Behdad Esfahbod 已提交
152 153 154 155
  friend struct Anchor;

  private:
  inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
156 157
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170
      /* TODO Contour */
      *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
      *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;
  }

  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 已提交
171 172
struct AnchorFormat3
{
B
Behdad Esfahbod 已提交
173 174 175 176
  friend struct Anchor;

  private:
  inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
177 178
			  hb_position_t *x, hb_position_t *y) const
  {
179 180 181 182 183 184 185 186
      *x = layout->gpos_info.x_scale * xCoordinate / 0x10000;
      *y = layout->gpos_info.y_scale * yCoordinate / 0x10000;

      if (!layout->gpos_info.dvi)
      {
	*x += (this+xDeviceTable).get_delta (layout->gpos_info.x_ppem) << 6;
	*y += (this+yDeviceTable).get_delta (layout->gpos_info.y_ppem) << 6;
      }
B
Behdad Esfahbod 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
  }

  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 已提交
204 205
struct Anchor
{
B
Behdad Esfahbod 已提交
206
  inline void get_anchor (hb_ot_layout_t *layout, hb_codepoint_t glyph_id,
B
Behdad Esfahbod 已提交
207 208
			  hb_position_t *x, hb_position_t *y) const
  {
B
Behdad Esfahbod 已提交
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
    *x = *y = 0;
    switch (u.format) {
    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;
    default:						    return;
    }
  }

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


B
Behdad Esfahbod 已提交
229 230
struct MarkRecord
{
231
  friend struct MarkArray;
B
Behdad Esfahbod 已提交
232 233 234 235 236 237 238 239 240

  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 已提交
241 242
struct MarkArray
{
B
Behdad Esfahbod 已提交
243 244
  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 已提交
245 246 247 248 249 250 251 252 253 254

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


/* Lookups */

B
Behdad Esfahbod 已提交
255 256
struct SinglePosFormat1
{
B
Behdad Esfahbod 已提交
257 258 259
  friend struct SinglePos;

  private:
B
Behdad Esfahbod 已提交
260 261
  inline bool apply (APPLY_ARG_DEF) const
  {
262 263 264 265 266 267
    unsigned int index = (this+coverage) (IN_CURGLYPH ());
    if (HB_LIKELY (index == NOT_COVERED))
      return false;

    valueFormat.apply_value (layout, (const char *) this, values, CURPOSITION ());
    return true;
B
Behdad Esfahbod 已提交
268 269 270 271 272 273 274
  }

  private:
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
275
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
276 277 278 279 280 281 282
					 * ValueRecord */
  ValueRecord	values;			/* Defines positioning
					 * value(s)--applied to all glyphs in
					 * the Coverage table */
};
ASSERT_SIZE (SinglePosFormat1, 6);

B
Behdad Esfahbod 已提交
283 284
struct SinglePosFormat2
{
B
Behdad Esfahbod 已提交
285 286 287
  friend struct SinglePos;

  private:
B
Behdad Esfahbod 已提交
288 289
  inline bool apply (APPLY_ARG_DEF) const
  {
290 291 292 293 294 295 296 297 298 299 300
    unsigned int index = (this+coverage) (IN_CURGLYPH ());
    if (HB_LIKELY (index == NOT_COVERED))
      return false;

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

    valueFormat.apply_value (layout, (const char *) this,
			     values + index * valueFormat.get_len (),
			     CURPOSITION ());
    return true;
B
Behdad Esfahbod 已提交
301 302 303 304 305 306 307
  }

  private:
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
308
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
309 310 311 312 313 314 315
					 * ValueRecord */
  USHORT	valueCount;		/* Number of ValueRecords */
  ValueRecord	values;			/* Array of ValueRecords--positioning
					 * values applied to glyphs */
};
ASSERT_SIZE (SinglePosFormat2, 8);

B
Behdad Esfahbod 已提交
316 317
struct SinglePos
{
B
Behdad Esfahbod 已提交
318 319 320
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
321 322
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
323
    switch (u.format) {
324 325
    case 1: return u.format1->apply (APPLY_ARG);
    case 2: return u.format2->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
326 327 328 329 330 331 332 333 334 335 336 337 338 339
    default:return false;
    }
  }

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


B
Behdad Esfahbod 已提交
340 341
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
342
  friend struct PairPosFormat1;
B
Behdad Esfahbod 已提交
343 344 345 346 347 348 349 350 351 352

  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 已提交
353 354
struct PairSet
{
B
Behdad Esfahbod 已提交
355 356 357 358 359 360 361 362 363
  friend struct PairPosFormat1;

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

B
Behdad Esfahbod 已提交
366 367
struct PairPosFormat1
{
B
Behdad Esfahbod 已提交
368 369 370
  friend struct PairPos;

  private:
B
Behdad Esfahbod 已提交
371 372 373 374 375 376 377 378 379 380 381
  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;
B
Behdad Esfahbod 已提交
382
    while (!_hb_ot_layout_check_glyph_property (layout, IN_INFO (j), lookup_flag, &property))
B
Behdad Esfahbod 已提交
383
    {
B
Behdad Esfahbod 已提交
384 385 386 387 388 389 390
      if (HB_UNLIKELY (j == end))
	return false;
      j++;
    }

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

B
Behdad Esfahbod 已提交
391 392
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
B
Behdad Esfahbod 已提交
393 394 395 396
    unsigned int record_len = 1 + len1 + len2;

    unsigned int count = pair_set.len;
    const PairValueRecord *record = pair_set.array;
B
Behdad Esfahbod 已提交
397 398 399 400
    for (unsigned int i = 0; i < count; i++)
    {
      if (IN_GLYPH (j) == record->secondGlyph)
      {
B
Behdad Esfahbod 已提交
401 402 403 404 405 406 407 408 409 410
	valueFormat1.apply_value (layout, (const char *) this, record->values, CURPOSITION ());
	valueFormat2.apply_value (layout, (const char *) this, record->values + len1, POSITION (j));
	if (len2)
	  j++;
	buffer->in_pos = j;
	return true;
      }
      record += record_len;
    }

B
Behdad Esfahbod 已提交
411 412 413 414 415 416 417 418
    return false;
  }

  private:
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
419
  ValueFormat	valueFormat1;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
420 421
					 * ValueRecord1--for the first glyph
					 * in the pair--may be zero (0) */
422
  ValueFormat	valueFormat2;		/* Defines the types of data in
B
Behdad Esfahbod 已提交
423 424 425 426 427 428 429 430
					 * 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 已提交
431 432
struct PairPosFormat2
{
B
Behdad Esfahbod 已提交
433 434 435
  friend struct PairPos;

  private:
B
Behdad Esfahbod 已提交
436 437 438 439 440 441 442 443 444 445 446
  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;
B
Behdad Esfahbod 已提交
447
    while (!_hb_ot_layout_check_glyph_property (layout, IN_INFO (j), lookup_flag, &property))
B
Behdad Esfahbod 已提交
448
    {
B
Behdad Esfahbod 已提交
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
      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);
    valueFormat1.apply_value (layout, (const char *) this, v, CURPOSITION ());
    valueFormat2.apply_value (layout, (const char *) this, v + len1, POSITION (j));

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

    return true;
B
Behdad Esfahbod 已提交
472 473
  }

B
Behdad Esfahbod 已提交
474

B
Behdad Esfahbod 已提交
475 476 477 478 479
  private:
  USHORT	format;			/* Format identifier--format = 2 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
480
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
481 482
					 * first glyph of the pair--may be zero
					 * (0) */
483
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
					 * 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 已提交
504 505
struct PairPos
{
B
Behdad Esfahbod 已提交
506 507 508
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
509 510
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
511
    switch (u.format) {
512 513
    case 1: return u.format1->apply (APPLY_ARG);
    case 2: return u.format2->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
514 515 516 517 518 519 520 521 522 523 524 525 526 527
    default:return false;
    }
  }

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


B
Behdad Esfahbod 已提交
528 529
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
530 531 532 533 534 535 536 537 538 539 540
  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 已提交
541 542
struct CursivePosFormat1
{
B
Behdad Esfahbod 已提交
543 544 545
  friend struct CursivePos;

  private:
B
Behdad Esfahbod 已提交
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 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
  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.        */

B
Behdad Esfahbod 已提交
665 666
    struct hb_ot_layout_t::gpos_info_t *gpi = &layout->gpos_info;
    hb_codepoint_t last_pos = gpi->last;
B
Behdad Esfahbod 已提交
667
    gpi->last = HB_OT_LAYOUT_GPOS_NO_LAST;
B
Behdad Esfahbod 已提交
668 669 670 671 672 673 674 675 676

    /* 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 已提交
677 678 679 680
    const EntryExitRecord &record = entryExitRecord[index];

    hb_position_t entry_x, entry_y, exit_x, exit_y;

B
Behdad Esfahbod 已提交
681
    if (last_pos == HB_OT_LAYOUT_GPOS_NO_LAST || !record.entryAnchor)
B
Behdad Esfahbod 已提交
682 683 684 685 686 687 688 689 690 691 692
      goto end;

    (this+record.entryAnchor).get_anchor (layout, IN_CURGLYPH (), &entry_x, &entry_y);

    if (gpi->r2l)
    {
      POSITION (buffer->in_pos)->x_advance   = entry_x - gpi->anchor_x;
      POSITION (buffer->in_pos)->new_advance = TRUE;
    }
    else
    {
B
Behdad Esfahbod 已提交
693 694
      POSITION (last_pos)->x_advance   = gpi->anchor_x - entry_x;
      POSITION (last_pos)->new_advance = TRUE;
B
Behdad Esfahbod 已提交
695 696 697 698
    }

    if  (lookup_flag & LookupFlag::RightToLeft)
    {
B
Behdad Esfahbod 已提交
699 700
      POSITION (last_pos)->cursive_chain = last_pos - buffer->in_pos;
      POSITION (last_pos)->y_pos = entry_y - gpi->anchor_y;
B
Behdad Esfahbod 已提交
701 702 703
    }
    else
    {
B
Behdad Esfahbod 已提交
704
      POSITION (buffer->in_pos)->cursive_chain = buffer->in_pos - last_pos;
B
Behdad Esfahbod 已提交
705 706 707 708 709
      POSITION (buffer->in_pos)->y_pos = gpi->anchor_y - entry_y;
    }

  end:
    if (record.exitAnchor)
B
Behdad Esfahbod 已提交
710 711
    {
      gpi->last = buffer->in_pos;
B
Behdad Esfahbod 已提交
712
      (this+record.exitAnchor).get_anchor (layout, IN_CURGLYPH (), &gpi->anchor_x, &gpi->anchor_y);
B
Behdad Esfahbod 已提交
713
    }
B
Behdad Esfahbod 已提交
714 715 716

    buffer->in_pos++;
    return true;
B
Behdad Esfahbod 已提交
717 718 719 720 721 722 723 724 725 726 727 728 729
  }

  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 已提交
730 731
struct CursivePos
{
B
Behdad Esfahbod 已提交
732 733 734
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
735 736
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
737
    switch (u.format) {
738
    case 1: return u.format1->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
739 740 741 742 743 744 745 746 747 748 749 750 751
    default:return false;
    }
  }

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


B
Behdad Esfahbod 已提交
752 753
struct BaseArray
{
B
Behdad Esfahbod 已提交
754
  friend struct MarkBasePosFormat1;
B
Behdad Esfahbod 已提交
755 756

  private:
B
Behdad Esfahbod 已提交
757 758 759 760 761 762 763
  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 已提交
764 765 766
};
ASSERT_SIZE (BaseArray, 2);

B
Behdad Esfahbod 已提交
767 768
struct MarkBasePosFormat1
{
B
Behdad Esfahbod 已提交
769 770 771
  friend struct MarkBasePos;

  private:
B
Behdad Esfahbod 已提交
772 773
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
774 775 776 777 778 779 780 781 782 783 784 785 786
    if  (lookup_flag & LookupFlag::IgnoreBaseGlyphs)
      return false;

    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;
    while (i <= count)
    {
      property = _hb_ot_layout_get_glyph_property (layout, IN_GLYPH (j));
B
Behdad Esfahbod 已提交
787
      if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & LookupFlag::MarkAttachmentType))
B
Behdad Esfahbod 已提交
788 789 790 791 792 793 794
	break;
      i++, j--;
    }
    if (HB_UNLIKELY (i > buffer->in_pos))
      return false;

    /* The following assertion is too strong -- at least for mangal.ttf. */
B
Behdad Esfahbod 已提交
795
#if 0
B
Behdad Esfahbod 已提交
796 797
    if (property != HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH)
      return false;
B
Behdad Esfahbod 已提交
798
#endif
B
Behdad Esfahbod 已提交
799 800

    unsigned int base_index = (this+baseCoverage) (IN_GLYPH (j));
B
Behdad Esfahbod 已提交
801
    if (base_index == NOT_COVERED)
B
Behdad Esfahbod 已提交
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
      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;

    mark_anchor.get_anchor (layout, IN_CURGLYPH (), &mark_x, &mark_y);
    unsigned int index = base_index * classCount + mark_class;
    (&base_array+base_array.matrix[index]).get_anchor (layout, IN_GLYPH (j), &base_x, &base_y);

B
Behdad Esfahbod 已提交
819
    hb_glyph_position_t *o = POSITION (buffer->in_pos);
B
Behdad Esfahbod 已提交
820 821 822 823 824 825 826 827
    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 已提交
828 829 830 831
  }

  private:
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
832 833
  OffsetTo<Coverage>
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
834
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
835 836
  OffsetTo<Coverage>
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
837 838
					 * beginning of MarkBasePos subtable */
  USHORT	classCount;		/* Number of classes defined for marks */
B
Behdad Esfahbod 已提交
839 840
  OffsetTo<MarkArray>
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
841
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
842 843
  OffsetTo<BaseArray>
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
844 845 846 847
					 * beginning of MarkBasePos subtable */
};
ASSERT_SIZE (MarkBasePosFormat1, 12);

B
Behdad Esfahbod 已提交
848 849
struct MarkBasePos
{
B
Behdad Esfahbod 已提交
850 851 852
  friend struct PosLookupSubTable;

  private:
B
Behdad Esfahbod 已提交
853 854
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
855
    switch (u.format) {
856
    case 1: return u.format1->apply (APPLY_ARG);
B
Behdad Esfahbod 已提交
857 858 859 860 861 862 863 864 865 866 867 868 869
    default:return false;
    }
  }

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


B
Behdad Esfahbod 已提交
870 871
struct LigatureAttach
{
B
Behdad Esfahbod 已提交
872
  friend struct MarkLigPosFormat1;
B
Behdad Esfahbod 已提交
873 874

  private:
B
Behdad Esfahbod 已提交
875 876 877 878 879 880 881 882
  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 已提交
883 884 885
};
ASSERT_SIZE (LigatureAttach, 2);

B
Behdad Esfahbod 已提交
886 887
typedef OffsetArrayOf<LigatureAttach> LigatureArray;
					/* Array of LigatureAttach
B
Behdad Esfahbod 已提交
888 889 890 891
					 * tables ordered by
					 * LigatureCoverage Index */
ASSERT_SIZE (LigatureArray, 2);

B
Behdad Esfahbod 已提交
892 893
struct MarkLigPosFormat1
{
B
Behdad Esfahbod 已提交
894 895 896
  friend struct MarkLigPos;

  private:
B
Behdad Esfahbod 已提交
897 898
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962
    if  (lookup_flag & LookupFlag::IgnoreLigatures)
      return false;

    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;
    while (i <= count)
    {
      property = _hb_ot_layout_get_glyph_property (layout, IN_GLYPH (j));
      if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & LookupFlag::MarkAttachmentType))
	break;
      i++, j--;
    }
    if (HB_UNLIKELY (i > buffer->in_pos))
      return false;

    /* The following assertion is too strong -- at least for mangal.ttf. */
#if 0
    if (property != HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
      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;

    mark_anchor.get_anchor (layout, IN_CURGLYPH (), &mark_x, &mark_y);
    unsigned int index = comp_index * classCount + mark_class;
    (&lig_attach+lig_attach.matrix[index]).get_anchor (layout, IN_GLYPH (j), &lig_x, &lig_y);

B
Behdad Esfahbod 已提交
963
    hb_glyph_position_t *o = POSITION (buffer->in_pos);
B
Behdad Esfahbod 已提交
964 965 966 967 968 969 970 971
    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 已提交
972 973 974 975
  }

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

B
Behdad Esfahbod 已提交
993 994
struct MarkLigPos
{
B
Behdad Esfahbod 已提交
995 996 997
  friend struct PosLookupSubTable;

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

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


B
Behdad Esfahbod 已提交
1015 1016
struct Mark2Array
{
B
Behdad Esfahbod 已提交
1017
  friend struct MarkMarkPosFormat1;
B
Behdad Esfahbod 已提交
1018 1019

  private:
B
Behdad Esfahbod 已提交
1020 1021 1022 1023 1024 1025 1026
  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 已提交
1027 1028 1029
};
ASSERT_SIZE (Mark2Array, 2);

B
Behdad Esfahbod 已提交
1030 1031
struct MarkMarkPosFormat1
{
B
Behdad Esfahbod 已提交
1032 1033 1034
  friend struct MarkMarkPos;

  private:
B
Behdad Esfahbod 已提交
1035 1036
  inline bool apply (APPLY_ARG_DEF) const
  {
B
Behdad Esfahbod 已提交
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
    if  (lookup_flag & LookupFlag::IgnoreMarks)
      return false;

    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;
    while (i <= count)
    {
      property = _hb_ot_layout_get_glyph_property (layout, IN_GLYPH (j));
      if (!(property == HB_OT_LAYOUT_GLYPH_CLASS_MARK || property & LookupFlag::MarkAttachmentType))
        return false;
      if (!(lookup_flag & LookupFlag::MarkAttachmentType) ||
	   (lookup_flag & LookupFlag::MarkAttachmentType) == property)
        break;
      i++, j--;
    }
    if (HB_UNLIKELY (i > buffer->in_pos))
      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;

    mark1_anchor.get_anchor (layout, IN_CURGLYPH (), &mark1_x, &mark1_y);
    unsigned int index = mark2_index * classCount + mark1_class;
    (&mark2_array+mark2_array.matrix[index]).get_anchor (layout, IN_GLYPH (j), &mark2_x, &mark2_y);

B
Behdad Esfahbod 已提交
1079
    hb_glyph_position_t *o = POSITION (buffer->in_pos);
B
Behdad Esfahbod 已提交
1080 1081 1082 1083 1084 1085 1086 1087
    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 已提交
1088 1089 1090 1091
  }

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

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

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

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


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

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

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

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

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


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

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


1165

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


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

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

1187
  bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const
B
Behdad Esfahbod 已提交
1188
  {
B
Behdad Esfahbod 已提交
1189
    switch (lookup_type) {
1190 1191 1192 1193 1194 1195 1196 1197 1198
    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 已提交
1199 1200 1201 1202 1203 1204
    default:return false;
    }
  }

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


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

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

1231
    if (HB_UNLIKELY (type == PosLookupSubTable::Extension))
B
Behdad Esfahbod 已提交
1232
    {
B
Behdad Esfahbod 已提交
1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
      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;
  }

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

B
Behdad Esfahbod 已提交
1254
    if (!_hb_ot_layout_check_glyph_property (layout, IN_CURINFO (), lookup_flag, &property))
1255
      return false;
B
Behdad Esfahbod 已提交
1256 1257

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

    return false;
  }

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

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

B
Behdad Esfahbod 已提交
1273
    layout->gpos_info.last = HB_OT_LAYOUT_GPOS_NO_LAST; /* no last valid glyph for cursive pos. */
1274

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

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

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


/*
 * GPOS
 */

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

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

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

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

};
ASSERT_SIZE (GPOS, 10);


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

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

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

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

B
Behdad Esfahbod 已提交
1338 1339
static inline bool position_lookup (APPLY_ARG_DEF, unsigned int lookup_index)
{
B
Behdad Esfahbod 已提交
1340 1341 1342 1343 1344 1345 1346 1347 1348 1349
  const GPOS &gpos = *(layout->gpos);
  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;

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


#endif /* HB_OT_LAYOUT_GPOS_PRIVATE_H */