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

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

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

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

P
pssea 已提交
37 38 39 40 41
struct MarkArray;
static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
						 const MarkArray &mark_array,
						 const hb_set_t  &glyphset,
						 hb_map_t*        klass_mapping /* INOUT */);
B
Behdad Esfahbod 已提交
42

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

enum attach_type_t {
  ATTACH_TYPE_NONE	= 0X00,

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


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

B
Behdad Esfahbod 已提交
59
typedef HBUINT16 Value;
60

B
Behdad Esfahbod 已提交
61
typedef UnsizedArrayOf<Value> ValueRecord;
B
Behdad Esfahbod 已提交
62

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

77
    devices	= 0x00F0u	/* Mask for having any Device table */
B
WIP  
Behdad Esfahbod 已提交
78
  };
79

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

L
lancer 已提交
106 107
  IntType& operator = (uint16_t i) { v = i; return *this; }

108 109
  unsigned int get_len () const  { return hb_popcount ((unsigned int) *this); }
  unsigned int get_size () const { return get_len () * Value::static_size; }
B
WIP  
Behdad Esfahbod 已提交
110

P
pssea 已提交
111 112 113 114
  bool apply_value (hb_ot_apply_context_t *c,
		    const void            *base,
		    const Value           *values,
		    hb_glyph_position_t   &glyph_pos) const
B
WIP  
Behdad Esfahbod 已提交
115
  {
116
    bool ret = false;
B
WIP  
Behdad Esfahbod 已提交
117
    unsigned int format = *this;
118
    if (!format) return ret;
B
WIP  
Behdad Esfahbod 已提交
119

120
    hb_font_t *font = c->font;
121
    bool horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction);
122

123 124
    if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++, &ret));
    if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++, &ret));
125
    if (format & xAdvance) {
126
      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values, &ret));
K
Konstantin Ritt 已提交
127
      values++;
128
    }
129
    /* y_advance values grow downward but font-space grows upward, hence negation */
130
    if (format & yAdvance) {
131
      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values, &ret));
K
Konstantin Ritt 已提交
132
      values++;
133
    }
134

135
    if (!has_device ()) return ret;
B
Behdad Esfahbod 已提交
136

137 138
    bool use_x_device = font->x_ppem || font->num_coords;
    bool use_y_device = font->y_ppem || font->num_coords;
B
Behdad Esfahbod 已提交
139

140
    if (!use_x_device && !use_y_device) return ret;
B
Behdad Esfahbod 已提交
141

142
    const VariationStore &store = c->var_store;
143

144 145
    /* pixel -> fractional pixel */
    if (format & xPlaDevice) {
146
      if (use_x_device) glyph_pos.x_offset  += (base + get_device (values, &ret)).get_x_delta (font, store);
K
Konstantin Ritt 已提交
147
      values++;
148 149
    }
    if (format & yPlaDevice) {
150
      if (use_y_device) glyph_pos.y_offset  += (base + get_device (values, &ret)).get_y_delta (font, store);
K
Konstantin Ritt 已提交
151
      values++;
152 153
    }
    if (format & xAdvDevice) {
154
      if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values, &ret)).get_x_delta (font, store);
K
Konstantin Ritt 已提交
155
      values++;
156 157
    }
    if (format & yAdvDevice) {
158
      /* y_advance values grow downward but font-space grows upward, hence negation */
159
      if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values, &ret)).get_y_delta (font, store);
K
Konstantin Ritt 已提交
160
      values++;
161
    }
162
    return ret;
163
  }
B
WIP  
Behdad Esfahbod 已提交
164

L
lancer 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
  unsigned int get_effective_format (const Value *values) const
  {
    unsigned int format = *this;
    for (unsigned flag = xPlacement; flag <= yAdvDevice; flag = flag << 1) {
      if (format & flag) should_drop (*values++, (Flags) flag, &format);
    }

    return format;
  }

  template<typename Iterator,
      hb_requires (hb_is_iterator (Iterator))>
  unsigned int get_effective_format (Iterator it) const {
    unsigned int new_format = 0;

    for (const hb_array_t<const Value>& values : it)
      new_format = new_format | get_effective_format (&values);

    return new_format;
  }

  void copy_values (hb_serialize_context_t *c,
                    unsigned int new_format,
                    const void *base,
                    const Value *values,
                    const hb_map_t *layout_variation_idx_map) const
P
pssea 已提交
191 192 193 194
  {
    unsigned int format = *this;
    if (!format) return;

L
lancer 已提交
195 196 197 198
    if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++);
    if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++);
    if (format & xAdvance)   copy_value (c, new_format, xAdvance, *values++);
    if (format & yAdvance)   copy_value (c, new_format, yAdvance, *values++);
P
pssea 已提交
199 200 201 202 203 204 205

    if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
    if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map);
    if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
    if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map);
  }

L
lancer 已提交
206 207 208 209 210 211 212 213 214 215
  void copy_value (hb_serialize_context_t *c,
                   unsigned int new_format,
                   Flags flag,
                   Value value) const
  {
    // Filter by new format.
    if (!(new_format & flag)) return;
    c->copy (value);
  }

P
pssea 已提交
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
				  const void *base,
				  const hb_array_t<const Value>& values) const
  {
    unsigned format = *this;
    unsigned i = 0;
    if (format & xPlacement) i++;
    if (format & yPlacement) i++;
    if (format & xAdvance) i++;
    if (format & yAdvance) i++;
    if (format & xPlaDevice)
    {
      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
      i++;
    }

    if (format & ValueFormat::yPlaDevice)
    {
      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
      i++;
    }

    if (format & ValueFormat::xAdvDevice)
    {

      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
      i++;
    }

    if (format & ValueFormat::yAdvDevice)
    {

      (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices);
      i++;
    }
  }

B
WIP  
Behdad Esfahbod 已提交
253
  private:
254
  bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
B
Behdad Esfahbod 已提交
255
  {
B
WIP  
Behdad Esfahbod 已提交
256 257 258 259 260 261 262
    unsigned int format = *this;

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

B
Behdad Esfahbod 已提交
263 264 265 266
    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
B
WIP  
Behdad Esfahbod 已提交
267 268 269 270

    return true;
  }

L
lancer 已提交
271
  static inline Offset16To<Device>& get_device (Value* value)
P
pssea 已提交
272
  {
L
lancer 已提交
273
    return *static_cast<Offset16To<Device> *> (value);
P
pssea 已提交
274
  }
L
lancer 已提交
275
  static inline const Offset16To<Device>& get_device (const Value* value, bool *worked=nullptr)
276
  {
B
Minor  
Behdad Esfahbod 已提交
277
    if (worked) *worked |= bool (*value);
L
lancer 已提交
278
    return *static_cast<const Offset16To<Device> *> (value);
279
  }
B
Behdad Esfahbod 已提交
280

P
pssea 已提交
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
  bool copy_device (hb_serialize_context_t *c, const void *base,
		    const Value *src_value, const hb_map_t *layout_variation_idx_map) const
  {
    Value	*dst_value = c->copy (*src_value);

    if (!dst_value) return false;
    if (*dst_value == 0) return true;

    *dst_value = 0;
    c->push ();
    if ((base + get_device (src_value)).copy (c, layout_variation_idx_map))
    {
      c->add_link (*dst_value, c->pop_pack ());
      return true;
    }
    else
    {
      c->pop_discard ();
      return false;
    }
  }

  static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr)
304
  {
B
Minor  
Behdad Esfahbod 已提交
305
    if (worked) *worked |= bool (*value);
P
pssea 已提交
306
    return *reinterpret_cast<const HBINT16 *> (value);
307
  }
B
Behdad Esfahbod 已提交
308

B
WIP  
Behdad Esfahbod 已提交
309 310
  public:

311
  bool has_device () const
312
  {
B
WIP  
Behdad Esfahbod 已提交
313 314 315 316
    unsigned int format = *this;
    return (format & devices) != 0;
  }

317
  bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
B
Behdad Esfahbod 已提交
318
  {
B
Behdad Esfahbod 已提交
319
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
320
    return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
B
WIP  
Behdad Esfahbod 已提交
321 322
  }

323
  bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
B
Behdad Esfahbod 已提交
324
  {
B
Behdad Esfahbod 已提交
325
    TRACE_SANITIZE (this);
B
WIP  
Behdad Esfahbod 已提交
326 327
    unsigned int len = get_len ();

328
    if (!c->check_range (values, count, get_size ())) return_trace (false);
B
WIP  
Behdad Esfahbod 已提交
329

B
Behdad Esfahbod 已提交
330
    if (!has_device ()) return_trace (true);
B
WIP  
Behdad Esfahbod 已提交
331 332

    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
333
      if (!sanitize_value_devices (c, base, values))
E
Ebrahim Byagowi 已提交
334
	return_trace (false);
B
WIP  
Behdad Esfahbod 已提交
335 336 337
      values += len;
    }

B
Behdad Esfahbod 已提交
338
    return_trace (true);
B
WIP  
Behdad Esfahbod 已提交
339 340
  }

B
Behdad Esfahbod 已提交
341
  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
342
  bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
B
Behdad Esfahbod 已提交
343
  {
B
Behdad Esfahbod 已提交
344
    TRACE_SANITIZE (this);
B
WIP  
Behdad Esfahbod 已提交
345

B
Behdad Esfahbod 已提交
346
    if (!has_device ()) return_trace (true);
B
WIP  
Behdad Esfahbod 已提交
347 348

    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
349
      if (!sanitize_value_devices (c, base, values))
E
Ebrahim Byagowi 已提交
350
	return_trace (false);
B
WIP  
Behdad Esfahbod 已提交
351 352 353
      values += stride;
    }

B
Behdad Esfahbod 已提交
354
    return_trace (true);
B
WIP  
Behdad Esfahbod 已提交
355
  }
L
lancer 已提交
356 357 358 359 360 361 362 363 364

 private:

  void should_drop (Value value, Flags flag, unsigned int* format) const
  {
    if (value) return;
    *format = *format & ~flag;
  }

B
Behdad Esfahbod 已提交
365 366
};

L
lancer 已提交
367
template<typename Iterator, typename SrcLookup>
P
pssea 已提交
368
static void SinglePos_serialize (hb_serialize_context_t *c,
L
lancer 已提交
369
				 const SrcLookup *src,
P
pssea 已提交
370 371
				 Iterator it,
				 const hb_map_t *layout_variation_idx_map);
372

B
Behdad Esfahbod 已提交
373

B
Behdad Esfahbod 已提交
374 375
struct AnchorFormat1
{
376 377
  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
		   float *x, float *y) const
B
Behdad Esfahbod 已提交
378
  {
379
    hb_font_t *font = c->font;
380 381
    *x = font->em_fscale_x (xCoordinate);
    *y = font->em_fscale_y (yCoordinate);
B
Behdad Esfahbod 已提交
382 383
  }

384
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
385
  {
B
Behdad Esfahbod 已提交
386
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
387
    return_trace (c->check_struct (this));
B
Behdad Esfahbod 已提交
388 389
  }

P
pssea 已提交
390 391 392
  AnchorFormat1* copy (hb_serialize_context_t *c) const
  {
    TRACE_SERIALIZE (this);
L
lancer 已提交
393 394 395 396
    AnchorFormat1* out = c->embed<AnchorFormat1> (this);
    if (!out) return_trace (out);
    out->format = 1;
    return_trace (out);
P
pssea 已提交
397 398
  }

399
  protected:
B
Behdad Esfahbod 已提交
400
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Minor  
Behdad Esfahbod 已提交
401 402
  FWORD		xCoordinate;		/* Horizontal value--in design units */
  FWORD		yCoordinate;		/* Vertical value--in design units */
403 404
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
405 406
};

B
Behdad Esfahbod 已提交
407 408
struct AnchorFormat2
{
409 410
  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
		   float *x, float *y) const
B
Behdad Esfahbod 已提交
411
  {
412
    hb_font_t *font = c->font;
413 414 415 416 417 418 419

#ifdef HB_NO_HINTING
    *x = font->em_fscale_x (xCoordinate);
    *y = font->em_fscale_y (yCoordinate);
    return;
#endif

420 421
    unsigned int x_ppem = font->x_ppem;
    unsigned int y_ppem = font->y_ppem;
422
    hb_position_t cx = 0, cy = 0;
423
    bool ret;
B
Behdad Esfahbod 已提交
424

425
    ret = (x_ppem || y_ppem) &&
426
	  font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
427 428
    *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
    *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
B
Behdad Esfahbod 已提交
429 430
  }

431
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
432
  {
B
Behdad Esfahbod 已提交
433
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
434
    return_trace (c->check_struct (this));
B
Behdad Esfahbod 已提交
435 436
  }

P
pssea 已提交
437 438 439 440 441 442
  AnchorFormat2* copy (hb_serialize_context_t *c) const
  {
    TRACE_SERIALIZE (this);
    return_trace (c->embed<AnchorFormat2> (this));
  }

443
  protected:
B
Behdad Esfahbod 已提交
444
  HBUINT16	format;			/* Format identifier--format = 2 */
B
Minor  
Behdad Esfahbod 已提交
445 446
  FWORD		xCoordinate;		/* Horizontal value--in design units */
  FWORD		yCoordinate;		/* Vertical value--in design units */
B
Behdad Esfahbod 已提交
447
  HBUINT16	anchorPoint;		/* Index to glyph contour point */
448 449
  public:
  DEFINE_SIZE_STATIC (8);
B
Behdad Esfahbod 已提交
450 451
};

B
Behdad Esfahbod 已提交
452 453
struct AnchorFormat3
{
454 455
  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
		   float *x, float *y) const
B
Behdad Esfahbod 已提交
456
  {
457
    hb_font_t *font = c->font;
458 459
    *x = font->em_fscale_x (xCoordinate);
    *y = font->em_fscale_y (yCoordinate);
460

461
    if (font->x_ppem || font->num_coords)
462
      *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
463
    if (font->y_ppem || font->num_coords)
B
Behdad Esfahbod 已提交
464
      *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
B
Behdad Esfahbod 已提交
465 466
  }

467
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
468
  {
B
Behdad Esfahbod 已提交
469
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
470
    return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
B
Behdad Esfahbod 已提交
471 472
  }

P
pssea 已提交
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
  AnchorFormat3* copy (hb_serialize_context_t *c,
		       const hb_map_t *layout_variation_idx_map) const
  {
    TRACE_SERIALIZE (this);
    if (!layout_variation_idx_map) return_trace (nullptr);

    auto *out = c->embed<AnchorFormat3> (this);
    if (unlikely (!out)) return_trace (nullptr);

    out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
    out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map);
    return_trace (out);
  }

  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices);
    (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices);
  }

493
  protected:
B
Behdad Esfahbod 已提交
494
  HBUINT16	format;			/* Format identifier--format = 3 */
B
Minor  
Behdad Esfahbod 已提交
495 496
  FWORD		xCoordinate;		/* Horizontal value--in design units */
  FWORD		yCoordinate;		/* Vertical value--in design units */
L
lancer 已提交
497
  Offset16To<Device>
B
Behdad Esfahbod 已提交
498 499 500
		xDeviceTable;		/* Offset to Device table for X
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
L
lancer 已提交
501
  Offset16To<Device>
B
Behdad Esfahbod 已提交
502 503 504
		yDeviceTable;		/* Offset to Device table for Y
					 * coordinate-- from beginning of
					 * Anchor table (may be NULL) */
505 506
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
507 508
};

B
Behdad Esfahbod 已提交
509 510
struct Anchor
{
511 512
  void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
		   float *x, float *y) const
B
Behdad Esfahbod 已提交
513
  {
B
Behdad Esfahbod 已提交
514 515
    *x = *y = 0;
    switch (u.format) {
516 517 518
    case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
    case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
    case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
519
    default:					      return;
B
Behdad Esfahbod 已提交
520 521 522
    }
  }

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

L
lancer 已提交
535
  bool subset (hb_subset_context_t *c) const
P
pssea 已提交
536
  {
L
lancer 已提交
537
    TRACE_SUBSET (this);
P
pssea 已提交
538
    switch (u.format) {
L
lancer 已提交
539 540 541 542 543 544 545 546 547 548 549 550
    case 1: return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
    case 2:
      if (c->plan->drop_hints)
      {
        // AnchorFormat 2 just containins extra hinting information, so
        // if hints are being dropped convert to format 1.
        return_trace (bool (reinterpret_cast<Anchor *> (u.format1.copy (c->serializer))));
      }
      return_trace (bool (reinterpret_cast<Anchor *> (u.format2.copy (c->serializer))));
    case 3: return_trace (bool (reinterpret_cast<Anchor *> (u.format3.copy (c->serializer,
                                                                            c->plan->layout_variation_idx_map))));
    default:return_trace (false);
P
pssea 已提交
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
    }
  }

  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    switch (u.format) {
    case 1: case 2:
      return;
    case 3:
      u.format3.collect_variation_indices (c);
      return;
    default: return;
    }
  }

566
  protected:
B
Behdad Esfahbod 已提交
567
  union {
B
Behdad Esfahbod 已提交
568
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
569 570 571
  AnchorFormat1		format1;
  AnchorFormat2		format2;
  AnchorFormat3		format3;
B
Behdad Esfahbod 已提交
572
  } u;
B
Behdad Esfahbod 已提交
573
  public:
B
Behdad Esfahbod 已提交
574
  DEFINE_SIZE_UNION (2, format);
B
Behdad Esfahbod 已提交
575 576 577
};


578 579
struct AnchorMatrix
{
580 581 582
  const Anchor& get_anchor (unsigned int row, unsigned int col,
			    unsigned int cols, bool *found) const
  {
583
    *found = false;
P
pssea 已提交
584
    if (unlikely (row >= rows || col >= cols)) return Null (Anchor);
585 586
    *found = !matrixZ[row * cols + col].is_null ();
    return this+matrixZ[row * cols + col];
587 588
  }

P
pssea 已提交
589 590 591 592 593 594 595 596 597 598
  template <typename Iterator,
	    hb_requires (hb_is_iterator (Iterator))>
  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
				  Iterator index_iter) const
  {
    for (unsigned i : index_iter)
      (this+matrixZ[i]).collect_variation_indices (c);
  }

  template <typename Iterator,
L
lancer 已提交
599 600 601 602
      hb_requires (hb_is_iterator (Iterator))>
  bool subset (hb_subset_context_t *c,
               unsigned             num_rows,
               Iterator             index_iter) const
P
pssea 已提交
603
  {
L
lancer 已提交
604 605 606 607
    TRACE_SUBSET (this);

    auto *out = c->serializer->start_embed (this);

P
pssea 已提交
608
    if (!index_iter) return_trace (false);
L
lancer 已提交
609
    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
P
pssea 已提交
610

L
lancer 已提交
611
    out->rows = num_rows;
P
pssea 已提交
612 613
    for (const unsigned i : index_iter)
    {
L
lancer 已提交
614
      auto *offset = c->serializer->embed (matrixZ[i]);
P
pssea 已提交
615
      if (!offset) return_trace (false);
L
lancer 已提交
616
      offset->serialize_subset (c, matrixZ[i], this);
P
pssea 已提交
617 618 619 620 621
    }

    return_trace (true);
  }

622
  bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
B
Behdad Esfahbod 已提交
623
  {
B
Behdad Esfahbod 已提交
624
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
625
    if (!c->check_struct (this)) return_trace (false);
626
    if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
627
    unsigned int count = rows * cols;
628
    if (!c->check_array (matrixZ.arrayZ, count)) return_trace (false);
629
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
630 631
      if (!matrixZ[i].sanitize (c, this)) return_trace (false);
    return_trace (true);
632 633
  }

B
Behdad Esfahbod 已提交
634
  HBUINT16	rows;			/* Number of rows */
L
lancer 已提交
635
  UnsizedArrayOf<Offset16To<Anchor>>
636
		matrixZ;		/* Matrix of offsets to Anchor tables--
637
					 * from beginning of AnchorMatrix table */
B
Behdad Esfahbod 已提交
638
  public:
639
  DEFINE_SIZE_ARRAY (2, matrixZ);
640 641 642
};


B
Behdad Esfahbod 已提交
643 644
struct MarkRecord
{
645
  friend struct MarkArray;
B
Behdad Esfahbod 已提交
646

P
pssea 已提交
647
  unsigned get_class () const { return (unsigned) klass; }
648
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
B
Behdad Esfahbod 已提交
649
  {
B
Behdad Esfahbod 已提交
650
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
651
    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
652 653
  }

L
lancer 已提交
654 655 656
  MarkRecord *subset (hb_subset_context_t    *c,
                      const void             *src_base,
                      const hb_map_t         *klass_mapping) const
P
pssea 已提交
657
  {
L
lancer 已提交
658 659
    TRACE_SUBSET (this);
    auto *out = c->serializer->embed (this);
P
pssea 已提交
660 661 662
    if (unlikely (!out)) return_trace (nullptr);

    out->klass = klass_mapping->get (klass);
L
lancer 已提交
663
    out->markAnchor.serialize_subset (c, markAnchor, src_base);
P
pssea 已提交
664 665 666 667 668 669 670 671 672
    return_trace (out);
  }

  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
				  const void *src_base) const
  {
    (src_base+markAnchor).collect_variation_indices (c);
  }

673
  protected:
B
Behdad Esfahbod 已提交
674
  HBUINT16	klass;			/* Class defined for this mark */
L
lancer 已提交
675
  Offset16To<Anchor>
B
Behdad Esfahbod 已提交
676 677
		markAnchor;		/* Offset to Anchor table--from
					 * beginning of MarkArray table */
B
Behdad Esfahbod 已提交
678 679
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
680 681
};

L
lancer 已提交
682
struct MarkArray : Array16Of<MarkRecord>	/* Array of MarkRecords--in Coverage order */
B
Behdad Esfahbod 已提交
683
{
684 685 686 687
  bool apply (hb_ot_apply_context_t *c,
	      unsigned int mark_index, unsigned int glyph_index,
	      const AnchorMatrix &anchors, unsigned int class_count,
	      unsigned int glyph_pos) const
688
  {
B
Behdad Esfahbod 已提交
689
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
690
    hb_buffer_t *buffer = c->buffer;
L
lancer 已提交
691
    const MarkRecord &record = Array16Of<MarkRecord>::operator[](mark_index);
692 693 694
    unsigned int mark_class = record.klass;

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

701
    float mark_x, mark_y, base_x, base_y;
702

703
    buffer->unsafe_to_break (glyph_pos, buffer->idx);
704 705
    mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
    glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
706

B
Behdad Esfahbod 已提交
707
    hb_glyph_position_t &o = buffer->cur_pos();
708 709
    o.x_offset = roundf (base_x - mark_x);
    o.y_offset = roundf (base_y - mark_y);
710
    o.attach_type() = ATTACH_TYPE_MARK;
711
    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
712
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
713

B
Behdad Esfahbod 已提交
714
    buffer->idx++;
B
Behdad Esfahbod 已提交
715
    return_trace (true);
716
  }
B
Behdad Esfahbod 已提交
717

L
lancer 已提交
718 719 720 721 722
  template <typename Iterator,
      hb_requires (hb_is_iterator (Iterator))>
  bool subset (hb_subset_context_t *c,
               Iterator		    coverage,
               const hb_map_t      *klass_mapping) const
P
pssea 已提交
723
  {
L
lancer 已提交
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
    TRACE_SUBSET (this);
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();

    auto* out = c->serializer->start_embed (this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);

    auto mark_iter =
    + hb_zip (coverage, this->iter ())
    | hb_filter (glyphset, hb_first)
    | hb_map (hb_second)
    ;

    unsigned new_length = 0;
    for (const auto& mark_record : mark_iter) {
      if (unlikely (!mark_record.subset (c, this, klass_mapping)))
        return_trace (false);
      new_length++;
    }

    if (unlikely (!c->serializer->check_assign (out->len, new_length,
                                                HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)))
      return_trace (false);

P
pssea 已提交
747 748 749
    return_trace (true);
  }

750
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
751
  {
B
Behdad Esfahbod 已提交
752
    TRACE_SANITIZE (this);
L
lancer 已提交
753
    return_trace (Array16Of<MarkRecord>::sanitize (c, this));
B
Behdad Esfahbod 已提交
754
  }
B
Behdad Esfahbod 已提交
755 756 757 758 759
};


/* Lookups */

B
Behdad Esfahbod 已提交
760 761
struct SinglePosFormat1
{
762
  bool intersects (const hb_set_t *glyphs) const
763 764
  { return (this+coverage).intersects (glyphs); }

P
pssea 已提交
765 766 767 768 769 770 771 772 773 774 775 776 777 778
  void closure_lookups (hb_closure_lookups_context_t *c) const {}
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    if (!valueFormat.has_device ()) return;

    auto it =
    + hb_iter (this+coverage)
    | hb_filter (c->glyph_set)
    ;

    if (!it) return;
    valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ()));
  }

779
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
P
pssea 已提交
780
  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
781

782
  const Coverage &get_coverage () const { return this+coverage; }
783

L
lancer 已提交
784 785
  ValueFormat get_value_format () const { return valueFormat; }

786
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
787
  {
B
Behdad Esfahbod 已提交
788
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
789 790
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
791
    if (likely (index == NOT_COVERED)) return_trace (false);
792

793
    valueFormat.apply_value (c, this, values, buffer->cur_pos());
794

B
Behdad Esfahbod 已提交
795
    buffer->idx++;
B
Behdad Esfahbod 已提交
796
    return_trace (true);
B
Behdad Esfahbod 已提交
797 798
  }

799
  template<typename Iterator,
L
lancer 已提交
800 801
      typename SrcLookup,
      hb_requires (hb_is_iterator (Iterator))>
802
  void serialize (hb_serialize_context_t *c,
L
lancer 已提交
803
		  const SrcLookup *src,
804
		  Iterator it,
L
lancer 已提交
805
		  ValueFormat newFormat,
P
pssea 已提交
806
		  const hb_map_t *layout_variation_idx_map)
807
  {
L
lancer 已提交
808 809 810 811
    if (unlikely (!c->extend_min (*this))) return;
    if (unlikely (!c->check_assign (valueFormat,
                                    newFormat,
                                    HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
812

L
lancer 已提交
813 814 815 816 817 818 819
    for (const hb_array_t<const Value>& _ : + it | hb_map (hb_second))
    {
      src->get_value_format ().copy_values (c, newFormat, src,  &_, layout_variation_idx_map);
      // Only serialize the first entry in the iterator, the rest are assumed to
      // be the same.
      break;
    }
820 821 822 823 824 825

    auto glyphs =
    + it
    | hb_map_retains_sorting (hb_first)
    ;

L
lancer 已提交
826
    // TODO(garretrieger): serialize_subset this.
827 828 829
    coverage.serialize (c, this).serialize (c, glyphs);
  }

830
  bool subset (hb_subset_context_t *c) const
831 832
  {
    TRACE_SUBSET (this);
L
lancer 已提交
833
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
834 835 836 837 838
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    auto it =
    + hb_iter (this+coverage)
    | hb_filter (glyphset)
P
pssea 已提交
839 840
    | hb_map_retains_sorting (glyph_map)
    | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ())))
841 842 843
    ;

    bool ret = bool (it);
L
lancer 已提交
844
    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
845
    return_trace (ret);
846 847
  }

848
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
849
  {
B
Behdad Esfahbod 已提交
850
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
851 852 853
    return_trace (c->check_struct (this) &&
		  coverage.sanitize (c, this) &&
		  valueFormat.sanitize_value (c, this, values));
B
Behdad Esfahbod 已提交
854 855
  }

856
  protected:
B
Behdad Esfahbod 已提交
857
  HBUINT16	format;			/* Format identifier--format = 1 */
L
lancer 已提交
858
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
859 860
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
861
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
862 863 864 865
					 * ValueRecord */
  ValueRecord	values;			/* Defines positioning
					 * value(s)--applied to all glyphs in
					 * the Coverage table */
B
Behdad Esfahbod 已提交
866
  public:
867
  DEFINE_SIZE_ARRAY (6, values);
B
Behdad Esfahbod 已提交
868 869
};

B
Behdad Esfahbod 已提交
870 871
struct SinglePosFormat2
{
872
  bool intersects (const hb_set_t *glyphs) const
873 874
  { return (this+coverage).intersects (glyphs); }

P
pssea 已提交
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
  void closure_lookups (hb_closure_lookups_context_t *c) const {}
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    if (!valueFormat.has_device ()) return;

    auto it =
    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
    | hb_filter (c->glyph_set, hb_first)
    ;

    if (!it) return;

    unsigned sub_length = valueFormat.get_len ();
    const hb_array_t<const Value> values_array = values.as_array (valueCount * sub_length);

    for (unsigned i : + it
		      | hb_map (hb_second))
      valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length));

  }

896
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
P
pssea 已提交
897
  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
898

899
  const Coverage &get_coverage () const { return this+coverage; }
900

L
lancer 已提交
901 902
  ValueFormat get_value_format () const { return valueFormat; }

903
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
904
  {
B
Behdad Esfahbod 已提交
905
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
906 907
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
908
    if (likely (index == NOT_COVERED)) return_trace (false);
909

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

912
    valueFormat.apply_value (c, this,
B
Behdad Esfahbod 已提交
913
			     &values[index * valueFormat.get_len ()],
B
Behdad Esfahbod 已提交
914
			     buffer->cur_pos());
915

B
Behdad Esfahbod 已提交
916
    buffer->idx++;
B
Behdad Esfahbod 已提交
917
    return_trace (true);
B
Behdad Esfahbod 已提交
918 919
  }

920
  template<typename Iterator,
L
lancer 已提交
921 922
      typename SrcLookup,
      hb_requires (hb_is_iterator (Iterator))>
923
  void serialize (hb_serialize_context_t *c,
L
lancer 已提交
924
		  const SrcLookup *src,
925
		  Iterator it,
L
lancer 已提交
926
		  ValueFormat newFormat,
P
pssea 已提交
927
		  const hb_map_t *layout_variation_idx_map)
928
  {
P
pssea 已提交
929 930
    auto out = c->extend_min (*this);
    if (unlikely (!out)) return;
L
lancer 已提交
931 932
    if (unlikely (!c->check_assign (valueFormat, newFormat, HB_SERIALIZE_ERROR_INT_OVERFLOW))) return;
    if (unlikely (!c->check_assign (valueCount, it.len (), HB_SERIALIZE_ERROR_ARRAY_OVERFLOW))) return;
P
pssea 已提交
933

934 935
    + it
    | hb_map (hb_second)
P
pssea 已提交
936
    | hb_apply ([&] (hb_array_t<const Value> _)
L
lancer 已提交
937
    { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); })
938 939 940 941 942 943
    ;

    auto glyphs =
    + it
    | hb_map_retains_sorting (hb_first)
    ;
P
pssea 已提交
944

945 946 947
    coverage.serialize (c, this).serialize (c, glyphs);
  }

948
  bool subset (hb_subset_context_t *c) const
949 950
  {
    TRACE_SUBSET (this);
L
lancer 已提交
951
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
952 953 954
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    unsigned sub_length = valueFormat.get_len ();
P
pssea 已提交
955
    auto values_array = values.as_array (valueCount * sub_length);
956 957 958 959 960

    auto it =
    + hb_zip (this+coverage, hb_range ((unsigned) valueCount))
    | hb_filter (glyphset, hb_first)
    | hb_map_retains_sorting ([&] (const hb_pair_t<hb_codepoint_t, unsigned>& _)
P
pssea 已提交
961 962 963 964 965
			      {
				return hb_pair (glyph_map[_.first],
						values_array.sub_array (_.second * sub_length,
									sub_length));
			      })
966 967 968
    ;

    bool ret = bool (it);
L
lancer 已提交
969
    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map);
970
    return_trace (ret);
971 972
  }

973
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
974
  {
B
Behdad Esfahbod 已提交
975
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
976 977 978
    return_trace (c->check_struct (this) &&
		  coverage.sanitize (c, this) &&
		  valueFormat.sanitize_values (c, this, values, valueCount));
B
Behdad Esfahbod 已提交
979 980
  }

981
  protected:
B
Behdad Esfahbod 已提交
982
  HBUINT16	format;			/* Format identifier--format = 2 */
L
lancer 已提交
983
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
984 985
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
986
  ValueFormat	valueFormat;		/* Defines the types of data in the
B
Behdad Esfahbod 已提交
987
					 * ValueRecord */
B
Behdad Esfahbod 已提交
988
  HBUINT16	valueCount;		/* Number of ValueRecords */
B
Behdad Esfahbod 已提交
989 990
  ValueRecord	values;			/* Array of ValueRecords--positioning
					 * values applied to glyphs */
B
Behdad Esfahbod 已提交
991
  public:
992
  DEFINE_SIZE_ARRAY (8, values);
B
Behdad Esfahbod 已提交
993 994
};

B
Behdad Esfahbod 已提交
995 996
struct SinglePos
{
997 998 999 1000 1001 1002
  template<typename Iterator,
	   hb_requires (hb_is_iterator (Iterator))>
  unsigned get_format (Iterator glyph_val_iter_pairs)
  {
    hb_array_t<const Value> first_val_iter = hb_second (*glyph_val_iter_pairs);

P
pssea 已提交
1003 1004 1005 1006
    for (const auto iter : glyph_val_iter_pairs)
      for (const auto _ : hb_zip (iter.second, first_val_iter))
	if (_.first != _.second)
	  return 2;
1007

P
pssea 已提交
1008
    return 1;
1009 1010 1011 1012
  }


  template<typename Iterator,
L
lancer 已提交
1013 1014
      typename SrcLookup,
      hb_requires (hb_is_iterator (Iterator))>
1015
  void serialize (hb_serialize_context_t *c,
L
lancer 已提交
1016
		  const SrcLookup* src,
1017
		  Iterator glyph_val_iter_pairs,
P
pssea 已提交
1018
		  const hb_map_t *layout_variation_idx_map)
1019 1020 1021
  {
    if (unlikely (!c->extend_min (u.format))) return;
    unsigned format = 2;
L
lancer 已提交
1022
    ValueFormat new_format = src->get_value_format ();
1023

L
lancer 已提交
1024 1025 1026 1027 1028
    if (glyph_val_iter_pairs)
    {
      format = get_format (glyph_val_iter_pairs);
      new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second));
    }
1029 1030 1031

    u.format = format;
    switch (u.format) {
L
lancer 已提交
1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
    case 1: u.format1.serialize (c,
                                 src,
                                 glyph_val_iter_pairs,
                                 new_format,
                                 layout_variation_idx_map);
      return;
    case 2: u.format2.serialize (c,
                                 src,
                                 glyph_val_iter_pairs,
                                 new_format,
                                 layout_variation_idx_map);
      return;
1044 1045 1046 1047
    default:return;
    }
  }

1048
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1049
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1050
  {
1051
    TRACE_DISPATCH (this, u.format);
1052
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1053
    switch (u.format) {
1054 1055
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
1056
    default:return_trace (c->default_return_value ());
1057 1058 1059
    }
  }

1060
  protected:
B
Behdad Esfahbod 已提交
1061
  union {
B
Behdad Esfahbod 已提交
1062
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1063 1064
  SinglePosFormat1	format1;
  SinglePosFormat2	format2;
B
Behdad Esfahbod 已提交
1065 1066 1067
  } u;
};

L
lancer 已提交
1068
template<typename Iterator, typename SrcLookup>
P
pssea 已提交
1069
static void
1070
SinglePos_serialize (hb_serialize_context_t *c,
L
lancer 已提交
1071
		     const SrcLookup *src,
P
pssea 已提交
1072 1073
		     Iterator it,
		     const hb_map_t *layout_variation_idx_map)
L
lancer 已提交
1074
{ c->start_embed<SinglePos> ()->serialize (c, src, it, layout_variation_idx_map); }
1075

B
Behdad Esfahbod 已提交
1076

B
Behdad Esfahbod 已提交
1077 1078
struct PairValueRecord
{
B
Behdad Esfahbod 已提交
1079
  friend struct PairSet;
B
Behdad Esfahbod 已提交
1080

P
pssea 已提交
1081 1082 1083
  int cmp (hb_codepoint_t k) const
  { return secondGlyph.cmp (k); }

L
lancer 已提交
1084
  struct context_t
P
pssea 已提交
1085 1086 1087
  {
    const void 		*base;
    const ValueFormat	*valueFormats;
L
lancer 已提交
1088
    const ValueFormat	*newFormats;
P
pssea 已提交
1089 1090 1091 1092 1093
    unsigned		len1; /* valueFormats[0].get_len() */
    const hb_map_t 	*glyph_map;
    const hb_map_t      *layout_variation_idx_map;
  };

L
lancer 已提交
1094 1095
  bool subset (hb_subset_context_t *c,
               context_t *closure) const
P
pssea 已提交
1096 1097
  {
    TRACE_SERIALIZE (this);
L
lancer 已提交
1098 1099 1100
    auto *s = c->serializer;
    auto *out = s->start_embed (*this);
    if (unlikely (!s->extend_min (out))) return_trace (false);
P
pssea 已提交
1101 1102 1103

    out->secondGlyph = (*closure->glyph_map)[secondGlyph];

L
lancer 已提交
1104 1105 1106 1107 1108 1109 1110 1111 1112
    closure->valueFormats[0].copy_values (s,
                                          closure->newFormats[0],
                                          closure->base, &values[0],
                                          closure->layout_variation_idx_map);
    closure->valueFormats[1].copy_values (s,
                                          closure->newFormats[1],
                                          closure->base,
                                          &values[closure->len1],
                                          closure->layout_variation_idx_map);
P
pssea 已提交
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131

    return_trace (true);
  }

  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
				  const ValueFormat *valueFormats,
				  const void *base) const
  {
    unsigned record1_len = valueFormats[0].get_len ();
    unsigned record2_len = valueFormats[1].get_len ();
    const hb_array_t<const Value> values_array = values.as_array (record1_len + record2_len);

    if (valueFormats[0].has_device ())
      valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len));

    if (valueFormats[1].has_device ())
      valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len));
  }

L
lancer 已提交
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
  bool intersects (const hb_set_t& glyphset) const
  {
    return glyphset.has(secondGlyph);
  }

  const Value* get_values_1 () const
  {
    return &values[0];
  }

  const Value* get_values_2 (ValueFormat format1) const
  {
    return &values[format1.get_len ()];
  }

1147
  protected:
P
pssea 已提交
1148
  HBGlyphID	secondGlyph;		/* GlyphID of second glyph in the
B
Behdad Esfahbod 已提交
1149 1150 1151 1152
					 * pair--first glyph is listed in the
					 * Coverage table */
  ValueRecord	values;			/* Positioning data for the first glyph
					 * followed by for second glyph */
B
Behdad Esfahbod 已提交
1153
  public:
1154
  DEFINE_SIZE_ARRAY (2, values);
B
Behdad Esfahbod 已提交
1155 1156
};

B
Behdad Esfahbod 已提交
1157 1158
struct PairSet
{
B
Behdad Esfahbod 已提交
1159 1160
  friend struct PairPosFormat1;

1161
  bool intersects (const hb_set_t *glyphs,
B
Behdad Esfahbod 已提交
1162
		   const ValueFormat *valueFormats) const
1163
  {
B
Behdad Esfahbod 已提交
1164 1165
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
1166 1167
    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);

1168
    const PairValueRecord *record = &firstPairValueRecord;
1169 1170 1171 1172
    unsigned int count = len;
    for (unsigned int i = 0; i < count; i++)
    {
      if (glyphs->has (record->secondGlyph))
E
Ebrahim Byagowi 已提交
1173
	return true;
1174 1175 1176 1177 1178
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
    }
    return false;
  }

1179
  void collect_glyphs (hb_collect_glyphs_context_t *c,
P
pssea 已提交
1180
		       const ValueFormat *valueFormats) const
1181
  {
B
Behdad Esfahbod 已提交
1182 1183
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
B
Behdad Esfahbod 已提交
1184
    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
1185

1186
    const PairValueRecord *record = &firstPairValueRecord;
1187
    c->input->add_array (&record->secondGlyph, len, record_size);
1188 1189
  }

P
pssea 已提交
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
				  const ValueFormat *valueFormats) const
  {
    unsigned len1 = valueFormats[0].get_len ();
    unsigned len2 = valueFormats[1].get_len ();
    unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);

    const PairValueRecord *record = &firstPairValueRecord;
    unsigned count = len;
    for (unsigned i = 0; i < count; i++)
    {
      if (c->glyph_set->has (record->secondGlyph))
      { record->collect_variation_indices (c, valueFormats, this); }

      record = &StructAtOffset<const PairValueRecord> (record, record_size);
    }
  }

1208
  bool apply (hb_ot_apply_context_t *c,
P
pssea 已提交
1209 1210
	      const ValueFormat *valueFormats,
	      unsigned int pos) const
B
Behdad Esfahbod 已提交
1211
  {
B
Behdad Esfahbod 已提交
1212
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1213
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
1214 1215
    unsigned int len1 = valueFormats[0].get_len ();
    unsigned int len2 = valueFormats[1].get_len ();
B
Behdad Esfahbod 已提交
1216
    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
B
Behdad Esfahbod 已提交
1217

P
pssea 已提交
1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
    const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
						&firstPairValueRecord,
						len,
						record_size);
    if (record)
    {
      /* Note the intentional use of "|" instead of short-circuit "||". */
      if (valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()) |
	  valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]))
	buffer->unsafe_to_break (buffer->idx, pos + 1);
      if (len2)
	pos++;
      buffer->idx = pos;
      return_trace (true);
    }
    return_trace (false);
  }
1235

P
pssea 已提交
1236
  bool subset (hb_subset_context_t *c,
L
lancer 已提交
1237 1238
	       const ValueFormat valueFormats[2],
               const ValueFormat newFormats[2]) const
P
pssea 已提交
1239 1240 1241 1242 1243 1244 1245 1246
  {
    TRACE_SUBSET (this);
    auto snap = c->serializer->snapshot ();

    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    out->len = 0;

L
lancer 已提交
1247
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
P
pssea 已提交
1248 1249 1250 1251 1252 1253
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    unsigned len1 = valueFormats[0].get_len ();
    unsigned len2 = valueFormats[1].get_len ();
    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);

L
lancer 已提交
1254
    PairValueRecord::context_t context =
B
Behdad Esfahbod 已提交
1255
    {
P
pssea 已提交
1256 1257
      this,
      valueFormats,
L
lancer 已提交
1258
      newFormats,
P
pssea 已提交
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268
      len1,
      &glyph_map,
      c->plan->layout_variation_idx_map
    };

    const PairValueRecord *record = &firstPairValueRecord;
    unsigned count = len, num = 0;
    for (unsigned i = 0; i < count; i++)
    {
      if (glyphset.has (record->secondGlyph)
L
lancer 已提交
1269
	 && record->subset (c, &context)) num++;
P
pssea 已提交
1270
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
B
Behdad Esfahbod 已提交
1271 1272
    }

P
pssea 已提交
1273 1274 1275
    out->len = num;
    if (!num) c->serializer->revert (snap);
    return_trace (num);
B
Behdad Esfahbod 已提交
1276 1277
  }

1278 1279
  struct sanitize_closure_t
  {
B
Behdad Esfahbod 已提交
1280
    const ValueFormat *valueFormats;
B
Behdad Esfahbod 已提交
1281
    unsigned int len1; /* valueFormats[0].get_len() */
B
Behdad Esfahbod 已提交
1282 1283 1284
    unsigned int stride; /* 1 + len1 + len2 */
  };

1285
  bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
B
Behdad Esfahbod 已提交
1286
  {
B
Behdad Esfahbod 已提交
1287
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1288
    if (!(c->check_struct (this)
1289 1290 1291 1292
       && c->check_range (&firstPairValueRecord,
			  len,
			  HBUINT16::static_size,
			  closure->stride))) return_trace (false);
B
Behdad Esfahbod 已提交
1293 1294

    unsigned int count = len;
1295
    const PairValueRecord *record = &firstPairValueRecord;
P
pssea 已提交
1296 1297
    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) &&
		  closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride));
B
Behdad Esfahbod 已提交
1298 1299
  }

1300
  protected:
1301 1302 1303 1304
  HBUINT16		len;	/* Number of PairValueRecords */
  PairValueRecord	firstPairValueRecord;
				/* Array of PairValueRecords--ordered
				 * by GlyphID of the second glyph */
B
Behdad Esfahbod 已提交
1305
  public:
1306
  DEFINE_SIZE_MIN (2);
B
Behdad Esfahbod 已提交
1307
};
B
Behdad Esfahbod 已提交
1308

B
Behdad Esfahbod 已提交
1309 1310
struct PairPosFormat1
{
1311
  bool intersects (const hb_set_t *glyphs) const
1312
  {
1313 1314 1315 1316
    return
    + hb_zip (this+coverage, pairSet)
    | hb_filter (*glyphs, hb_first)
    | hb_map (hb_second)
L
lancer 已提交
1317
    | hb_map ([glyphs, this] (const Offset16To<PairSet> &_)
1318 1319 1320
	      { return (this+_).intersects (glyphs, valueFormat); })
    | hb_any
    ;
1321 1322
  }

P
pssea 已提交
1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340
  void closure_lookups (hb_closure_lookups_context_t *c) const {}
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return;

    auto it =
    + hb_zip (this+coverage, pairSet)
    | hb_filter (c->glyph_set, hb_first)
    | hb_map (hb_second)
    ;

    if (!it) return;
    + it
    | hb_map (hb_add (this))
    | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); })
    ;
  }

1341
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1342
  {
P
pssea 已提交
1343
    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
1344 1345
    unsigned int count = pairSet.len;
    for (unsigned int i = 0; i < count; i++)
1346
      (this+pairSet[i]).collect_glyphs (c, valueFormat);
1347 1348
  }

1349
  const Coverage &get_coverage () const { return this+coverage; }
1350

1351
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1352
  {
B
Behdad Esfahbod 已提交
1353
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1354 1355
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1356
    if (likely (index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
1357

1358
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1359
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
1360
    if (!skippy_iter.next ()) return_trace (false);
B
Behdad Esfahbod 已提交
1361

1362
    return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
B
Behdad Esfahbod 已提交
1363 1364
  }

1365
  bool subset (hb_subset_context_t *c) const
1366 1367
  {
    TRACE_SUBSET (this);
P
pssea 已提交
1368

L
lancer 已提交
1369
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
P
pssea 已提交
1370 1371 1372 1373 1374 1375 1376
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    out->format = format;
    out->valueFormat[0] = valueFormat[0];
    out->valueFormat[1] = valueFormat[1];
L
lancer 已提交
1377 1378 1379 1380 1381 1382
    if (c->plan->drop_hints)
    {
      hb_pair_t<unsigned, unsigned> newFormats = compute_effective_value_formats (glyphset);
      out->valueFormat[0] = newFormats.first;
      out->valueFormat[1] = newFormats.second;
    }
P
pssea 已提交
1383 1384 1385 1386 1387

    hb_sorted_vector_t<hb_codepoint_t> new_coverage;

    + hb_zip (this+coverage, pairSet)
    | hb_filter (glyphset, hb_first)
L
lancer 已提交
1388
    | hb_filter ([this, c, out] (const Offset16To<PairSet>& _)
P
pssea 已提交
1389 1390 1391 1392
		 {
		   auto *o = out->pairSet.serialize_append (c->serializer);
		   if (unlikely (!o)) return false;
		   auto snap = c->serializer->snapshot ();
L
lancer 已提交
1393
		   bool ret = o->serialize_subset (c, _, this, valueFormat, out->valueFormat);
P
pssea 已提交
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
		   if (!ret)
		   {
		     out->pairSet.pop ();
		     c->serializer->revert (snap);
		   }
		   return ret;
		 },
		 hb_second)
    | hb_map (hb_first)
    | hb_map (glyph_map)
    | hb_sink (new_coverage)
    ;

    out->coverage.serialize (c->serializer, out)
		 .serialize (c->serializer, new_coverage.iter ());

    return_trace (bool (new_coverage));
1411 1412
  }

L
lancer 已提交
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442

  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
  {
    unsigned len1 = valueFormat[0].get_len ();
    unsigned len2 = valueFormat[1].get_len ();
    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);

    unsigned format1 = 0;
    unsigned format2 = 0;
    for (const Offset16To<PairSet>& _ :
             + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second))
    {
      const PairSet& set = (this + _);
      const PairValueRecord *record = &set.firstPairValueRecord;

      for (unsigned i = 0; i < set.len; i++)
      {
        if (record->intersects (glyphset))
        {
          format1 = format1 | valueFormat[0].get_effective_format (record->get_values_1 ());
          format2 = format2 | valueFormat[1].get_effective_format (record->get_values_2 (valueFormat[0]));
        }
        record = &StructAtOffset<const PairValueRecord> (record, record_size);
      }
    }

    return hb_pair (format1, format2);
  }


1443
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1444
  {
B
Behdad Esfahbod 已提交
1445
    TRACE_SANITIZE (this);
1446

1447 1448
    if (!c->check_struct (this)) return_trace (false);

B
Behdad Esfahbod 已提交
1449 1450
    unsigned int len1 = valueFormat[0].get_len ();
    unsigned int len2 = valueFormat[1].get_len ();
1451 1452
    PairSet::sanitize_closure_t closure =
    {
1453
      valueFormat,
B
Behdad Esfahbod 已提交
1454 1455 1456
      len1,
      1 + len1 + len2
    };
1457

1458
    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
B
Behdad Esfahbod 已提交
1459 1460
  }

1461
  protected:
B
Behdad Esfahbod 已提交
1462
  HBUINT16	format;			/* Format identifier--format = 1 */
L
lancer 已提交
1463
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
1464 1465
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
B
Behdad Esfahbod 已提交
1466
  ValueFormat	valueFormat[2];		/* [0] Defines the types of data in
B
Behdad Esfahbod 已提交
1467 1468
					 * ValueRecord1--for the first glyph
					 * in the pair--may be zero (0) */
B
Behdad Esfahbod 已提交
1469
					/* [1] Defines the types of data in
B
Behdad Esfahbod 已提交
1470 1471
					 * ValueRecord2--for the second glyph
					 * in the pair--may be zero (0) */
L
lancer 已提交
1472
  Array16OfOffset16To<PairSet>
B
Behdad Esfahbod 已提交
1473 1474
		pairSet;		/* Array of PairSet tables
					 * ordered by Coverage Index */
1475
  public:
1476
  DEFINE_SIZE_ARRAY (10, pairSet);
B
Behdad Esfahbod 已提交
1477 1478
};

P
pssea 已提交
1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
struct PairPosFormat2
{
  bool intersects (const hb_set_t *glyphs) const
  {
    return (this+coverage).intersects (glyphs) &&
	   (this+classDef2).intersects (glyphs);
  }

  void closure_lookups (hb_closure_lookups_context_t *c) const {}
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
L
lancer 已提交
1490
    if (!intersects (c->glyph_set)) return;
P
pssea 已提交
1491 1492
    if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return;

L
lancer 已提交
1493 1494 1495 1496
    hb_set_t klass1_glyphs, klass2_glyphs;
    if (!(this+classDef1).collect_coverage (&klass1_glyphs)) return;
    if (!(this+classDef2).collect_coverage (&klass2_glyphs)) return;

P
pssea 已提交
1497
    hb_set_t class1_set, class2_set;
L
lancer 已提交
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509
    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (this + coverage))
    {
      if (!klass1_glyphs.has (cp)) class1_set.add (0);
      else
      {
        unsigned klass1 = (this+classDef1).get (cp);
        class1_set.add (klass1);
      }
    }

    class2_set.add (0);
    for (const unsigned cp : + c->glyph_set->iter () | hb_filter (klass2_glyphs))
P
pssea 已提交
1510 1511 1512 1513 1514
    {
      unsigned klass2 = (this+classDef2).get (cp);
      class2_set.add (klass2);
    }

L
lancer 已提交
1515 1516 1517 1518
    if (class1_set.is_empty ()
        || class2_set.is_empty ()
        || (class2_set.get_population() == 1 && class2_set.has(0)))
      return;
P
pssea 已提交
1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534

    unsigned len1 = valueFormat1.get_len ();
    unsigned len2 = valueFormat2.get_len ();
    const hb_array_t<const Value> values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2));
    for (const unsigned class1_idx : class1_set.iter ())
    {
      for (const unsigned class2_idx : class2_set.iter ())
      {
	unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
	if (valueFormat1.has_device ())
	  valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1));

	if (valueFormat2.has_device ())
	  valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2));
      }
    }
1535 1536
  }

1537
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1538
  {
P
pssea 已提交
1539 1540
    if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
    if (unlikely (!(this+classDef2).collect_coverage (c->input))) return;
1541 1542
  }

1543
  const Coverage &get_coverage () const { return this+coverage; }
1544

1545
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1546
  {
B
Behdad Esfahbod 已提交
1547
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1548 1549
    hb_buffer_t *buffer = c->buffer;
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1550
    if (likely (index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
1551

1552
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1553
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
1554
    if (!skippy_iter.next ()) return_trace (false);
B
Behdad Esfahbod 已提交
1555 1556 1557 1558 1559

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

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

B
Behdad Esfahbod 已提交
1564
    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
1565 1566 1567 1568
    /* Note the intentional use of "|" instead of short-circuit "||". */
    if (valueFormat1.apply_value (c, this, v, buffer->cur_pos()) |
	valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]))
      buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
B
Behdad Esfahbod 已提交
1569

B
Behdad Esfahbod 已提交
1570
    buffer->idx = skippy_iter.idx;
B
Behdad Esfahbod 已提交
1571
    if (len2)
B
Behdad Esfahbod 已提交
1572
      buffer->idx++;
B
Behdad Esfahbod 已提交
1573

B
Behdad Esfahbod 已提交
1574
    return_trace (true);
B
Behdad Esfahbod 已提交
1575 1576
  }

1577
  bool subset (hb_subset_context_t *c) const
1578 1579
  {
    TRACE_SUBSET (this);
P
pssea 已提交
1580 1581 1582 1583 1584
    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    out->format = format;

    hb_map_t klass1_map;
L
lancer 已提交
1585
    out->classDef1.serialize_subset (c, classDef1, this, &klass1_map, true, true, &(this + coverage));
P
pssea 已提交
1586 1587 1588
    out->class1Count = klass1_map.get_population ();

    hb_map_t klass2_map;
L
lancer 已提交
1589
    out->classDef2.serialize_subset (c, classDef2, this, &klass2_map, true, false);
P
pssea 已提交
1590 1591 1592 1593 1594
    out->class2Count = klass2_map.get_population ();

    unsigned len1 = valueFormat1.get_len ();
    unsigned len2 = valueFormat2.get_len ();

L
lancer 已提交
1595 1596 1597 1598 1599 1600
    hb_pair_t<unsigned, unsigned> newFormats = hb_pair (valueFormat1, valueFormat2);
    if (c->plan->drop_hints)
      newFormats = compute_effective_value_formats (klass1_map, klass2_map);

    out->valueFormat1 = newFormats.first;
    out->valueFormat2 = newFormats.second;
P
pssea 已提交
1601

L
lancer 已提交
1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
    {
      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
      {
        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
        valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map);
        valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map);
      }
    }

    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
P
pssea 已提交
1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    auto it =
    + hb_iter (this+coverage)
    | hb_filter (glyphset)
    | hb_map_retains_sorting (glyph_map)
    ;

    out->coverage.serialize (c->serializer, out).serialize (c->serializer, it);
    return_trace (out->class1Count && out->class2Count && bool (it));
  }

L
lancer 已提交
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648

  hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_map_t& klass1_map,
                                                                 const hb_map_t& klass2_map) const
  {
    unsigned len1 = valueFormat1.get_len ();
    unsigned len2 = valueFormat2.get_len ();

    unsigned format1 = 0;
    unsigned format2 = 0;

    for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map))
    {
      for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
      {
        unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
        format1 = format1 | valueFormat1.get_effective_format (&values[idx]);
        format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]);
      }
    }

    return hb_pair (format1, format2);
  }


1649
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1650
  {
B
Behdad Esfahbod 已提交
1651
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1652 1653 1654
    if (!(c->check_struct (this)
       && coverage.sanitize (c, this)
       && classDef1.sanitize (c, this)
B
Behdad Esfahbod 已提交
1655
       && classDef2.sanitize (c, this))) return_trace (false);
1656

1657 1658 1659
    unsigned int len1 = valueFormat1.get_len ();
    unsigned int len2 = valueFormat2.get_len ();
    unsigned int stride = len1 + len2;
B
Behdad Esfahbod 已提交
1660
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
1661
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
1662 1663 1664
    return_trace (c->check_range ((const void *) values,
				  count,
				  record_size) &&
B
Behdad Esfahbod 已提交
1665
		  valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
B
Behdad Esfahbod 已提交
1666
		  valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
B
Behdad Esfahbod 已提交
1667
  }
B
Behdad Esfahbod 已提交
1668

1669
  protected:
B
Behdad Esfahbod 已提交
1670
  HBUINT16	format;			/* Format identifier--format = 2 */
L
lancer 已提交
1671
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
1672 1673
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
1674
  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
1675 1676
					 * first glyph of the pair--may be zero
					 * (0) */
1677
  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
B
Behdad Esfahbod 已提交
1678 1679
					 * second glyph of the pair--may be
					 * zero (0) */
L
lancer 已提交
1680
  Offset16To<ClassDef>
B
Behdad Esfahbod 已提交
1681 1682 1683
		classDef1;		/* Offset to ClassDef table--from
					 * beginning of PairPos subtable--for
					 * the first glyph of the pair */
L
lancer 已提交
1684
  Offset16To<ClassDef>
B
Behdad Esfahbod 已提交
1685 1686 1687
		classDef2;		/* Offset to ClassDef table--from
					 * beginning of PairPos subtable--for
					 * the second glyph of the pair */
B
Behdad Esfahbod 已提交
1688
  HBUINT16	class1Count;		/* Number of classes in ClassDef1
B
Behdad Esfahbod 已提交
1689
					 * table--includes Class0 */
B
Behdad Esfahbod 已提交
1690
  HBUINT16	class2Count;		/* Number of classes in ClassDef2
B
Behdad Esfahbod 已提交
1691 1692 1693 1694
					 * table--includes Class0 */
  ValueRecord	values;			/* Matrix of value pairs:
					 * class1-major, class2-minor,
					 * Each entry has value1 and value2 */
B
Behdad Esfahbod 已提交
1695
  public:
1696
  DEFINE_SIZE_ARRAY (16, values);
B
Behdad Esfahbod 已提交
1697 1698
};

B
Behdad Esfahbod 已提交
1699 1700
struct PairPos
{
1701
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1702
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1703
  {
1704
    TRACE_DISPATCH (this, u.format);
1705
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1706
    switch (u.format) {
1707 1708
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
1709
    default:return_trace (c->default_return_value ());
1710 1711 1712
    }
  }

1713
  protected:
B
Behdad Esfahbod 已提交
1714
  union {
B
Behdad Esfahbod 已提交
1715
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1716 1717
  PairPosFormat1	format1;
  PairPosFormat2	format2;
B
Behdad Esfahbod 已提交
1718 1719 1720 1721
  } u;
};


B
Behdad Esfahbod 已提交
1722 1723
struct EntryExitRecord
{
B
Behdad Esfahbod 已提交
1724 1725
  friend struct CursivePosFormat1;

1726
  bool sanitize (hb_sanitize_context_t *c, const void *base) const
B
Behdad Esfahbod 已提交
1727
  {
B
Behdad Esfahbod 已提交
1728
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1729
    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
B
Behdad Esfahbod 已提交
1730 1731
  }

P
pssea 已提交
1732 1733 1734 1735 1736 1737 1738
  void collect_variation_indices (hb_collect_variation_indices_context_t *c,
				  const void *src_base) const
  {
    (src_base+entryAnchor).collect_variation_indices (c);
    (src_base+exitAnchor).collect_variation_indices (c);
  }

L
lancer 已提交
1739 1740
  EntryExitRecord* subset (hb_subset_context_t *c,
                           const void *src_base) const
P
pssea 已提交
1741 1742
  {
    TRACE_SERIALIZE (this);
L
lancer 已提交
1743
    auto *out = c->serializer->embed (this);
P
pssea 已提交
1744 1745
    if (unlikely (!out)) return_trace (nullptr);

L
lancer 已提交
1746 1747
    out->entryAnchor.serialize_subset (c, entryAnchor, src_base);
    out->exitAnchor.serialize_subset (c, exitAnchor, src_base);
P
pssea 已提交
1748 1749 1750
    return_trace (out);
  }

1751
  protected:
L
lancer 已提交
1752
  Offset16To<Anchor>
B
Behdad Esfahbod 已提交
1753 1754 1755
		entryAnchor;		/* Offset to EntryAnchor table--from
					 * beginning of CursivePos
					 * subtable--may be NULL */
L
lancer 已提交
1756
  Offset16To<Anchor>
B
Behdad Esfahbod 已提交
1757 1758 1759
		exitAnchor;		/* Offset to ExitAnchor table--from
					 * beginning of CursivePos
					 * subtable--may be NULL */
B
Behdad Esfahbod 已提交
1760 1761
  public:
  DEFINE_SIZE_STATIC (4);
B
Behdad Esfahbod 已提交
1762 1763
};

1764 1765 1766
static void
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);

B
Behdad Esfahbod 已提交
1767 1768
struct CursivePosFormat1
{
1769
  bool intersects (const hb_set_t *glyphs) const
1770 1771
  { return (this+coverage).intersects (glyphs); }

P
pssea 已提交
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782
  void closure_lookups (hb_closure_lookups_context_t *c) const {}

  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    + hb_zip (this+coverage, entryExitRecord)
    | hb_filter (c->glyph_set, hb_first)
    | hb_map (hb_second)
    | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); })
    ;
  }

1783
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
P
pssea 已提交
1784
  { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; }
1785

1786
  const Coverage &get_coverage () const { return this+coverage; }
1787

1788
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1789
  {
B
Behdad Esfahbod 已提交
1790
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1791
    hb_buffer_t *buffer = c->buffer;
B
Behdad Esfahbod 已提交
1792

B
Behdad Esfahbod 已提交
1793
    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
1794
    if (!this_record.entryAnchor) return_trace (false);
1795

1796
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1797
    skippy_iter.reset (buffer->idx, 1);
1798
    if (!skippy_iter.prev ()) return_trace (false);
1799

1800 1801
    const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
    if (!prev_record.exitAnchor) return_trace (false);
B
Behdad Esfahbod 已提交
1802

1803 1804
    unsigned int i = skippy_iter.idx;
    unsigned int j = buffer->idx;
B
Behdad Esfahbod 已提交
1805

1806
    buffer->unsafe_to_break (i, j);
1807
    float entry_x, entry_y, exit_x, exit_y;
1808 1809
    (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
    (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
B
Behdad Esfahbod 已提交
1810

B
Behdad Esfahbod 已提交
1811
    hb_glyph_position_t *pos = buffer->pos;
B
Behdad Esfahbod 已提交
1812 1813 1814 1815 1816

    hb_position_t d;
    /* Main-direction adjustment */
    switch (c->direction) {
      case HB_DIRECTION_LTR:
1817
	pos[i].x_advance  = roundf (exit_x) + pos[i].x_offset;
B
Behdad Esfahbod 已提交
1818

1819
	d = roundf (entry_x) + pos[j].x_offset;
B
Behdad Esfahbod 已提交
1820 1821 1822 1823
	pos[j].x_advance -= d;
	pos[j].x_offset  -= d;
	break;
      case HB_DIRECTION_RTL:
1824
	d = roundf (exit_x) + pos[i].x_offset;
B
Behdad Esfahbod 已提交
1825 1826 1827
	pos[i].x_advance -= d;
	pos[i].x_offset  -= d;

1828
	pos[j].x_advance  = roundf (entry_x) + pos[j].x_offset;
B
Behdad Esfahbod 已提交
1829 1830
	break;
      case HB_DIRECTION_TTB:
1831
	pos[i].y_advance  = roundf (exit_y) + pos[i].y_offset;
B
Behdad Esfahbod 已提交
1832

1833
	d = roundf (entry_y) + pos[j].y_offset;
B
Behdad Esfahbod 已提交
1834 1835 1836 1837
	pos[j].y_advance -= d;
	pos[j].y_offset  -= d;
	break;
      case HB_DIRECTION_BTT:
1838
	d = roundf (exit_y) + pos[i].y_offset;
B
Behdad Esfahbod 已提交
1839 1840 1841
	pos[i].y_advance -= d;
	pos[i].y_offset  -= d;

1842
	pos[j].y_advance  = roundf (entry_y);
B
Behdad Esfahbod 已提交
1843 1844 1845 1846
	break;
      case HB_DIRECTION_INVALID:
      default:
	break;
B
Behdad Esfahbod 已提交
1847 1848
    }

B
Behdad Esfahbod 已提交
1849
    /* Cross-direction adjustment */
1850 1851 1852 1853 1854 1855

    /* We attach child to parent (think graph theory and rooted trees whereas
     * the root stays on baseline and each node aligns itself against its
     * parent.
     *
     * Optimize things for the case of RightToLeft, as that's most common in
1856
     * Arabic. */
1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867
    unsigned int child  = i;
    unsigned int parent = j;
    hb_position_t x_offset = entry_x - exit_x;
    hb_position_t y_offset = entry_y - exit_y;
    if  (!(c->lookup_props & LookupFlag::RightToLeft))
    {
      unsigned int k = child;
      child = parent;
      parent = k;
      x_offset = -x_offset;
      y_offset = -y_offset;
B
Behdad Esfahbod 已提交
1868 1869
    }

1870 1871 1872 1873 1874 1875 1876
    /* If child was already connected to someone else, walk through its old
     * chain and reverse the link direction, such that the whole tree of its
     * previous connection now attaches to new parent.  Watch out for case
     * where new parent is on the path from old chain...
     */
    reverse_cursive_minor_offset (pos, child, c->direction, parent);

1877 1878
    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
    pos[child].attach_chain() = (int) parent - (int) child;
1879
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
1880 1881 1882 1883 1884
    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
      pos[child].y_offset = y_offset;
    else
      pos[child].x_offset = x_offset;

P
pssea 已提交
1885 1886 1887 1888 1889 1890
    /* If parent was attached to child, break them free.
     * https://github.com/harfbuzz/harfbuzz/issues/2469
     */
    if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain()))
      pos[parent].attach_chain() = 0;

1891
    buffer->idx++;
B
Behdad Esfahbod 已提交
1892
    return_trace (true);
B
Behdad Esfahbod 已提交
1893 1894
  }

P
pssea 已提交
1895 1896
  template <typename Iterator,
	    hb_requires (hb_is_iterator (Iterator))>
L
lancer 已提交
1897
  void serialize (hb_subset_context_t *c,
P
pssea 已提交
1898
		  Iterator it,
L
lancer 已提交
1899
		  const void *src_base)
P
pssea 已提交
1900
  {
L
lancer 已提交
1901
    if (unlikely (!c->serializer->extend_min ((*this)))) return;
P
pssea 已提交
1902 1903 1904 1905 1906
    this->format = 1;
    this->entryExitRecord.len = it.len ();

    for (const EntryExitRecord& entry_record : + it
					       | hb_map (hb_second))
L
lancer 已提交
1907
      entry_record.subset (c, src_base);
P
pssea 已提交
1908 1909 1910 1911 1912 1913

    auto glyphs =
    + it
    | hb_map_retains_sorting (hb_first)
    ;

L
lancer 已提交
1914
    coverage.serialize (c->serializer, this).serialize (c->serializer, glyphs);
P
pssea 已提交
1915 1916
  }

1917
  bool subset (hb_subset_context_t *c) const
1918 1919
  {
    TRACE_SUBSET (this);
L
lancer 已提交
1920
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
P
pssea 已提交
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!out)) return_trace (false);

    auto it =
    + hb_zip (this+coverage, entryExitRecord)
    | hb_filter (glyphset, hb_first)
    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const EntryExitRecord&> p) -> hb_pair_t<hb_codepoint_t, const EntryExitRecord&>
			      { return hb_pair (glyph_map[p.first], p.second);})
    ;

    bool ret = bool (it);
L
lancer 已提交
1934
    out->serialize (c, it, this);
P
pssea 已提交
1935
    return_trace (ret);
1936 1937
  }

1938
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1939
  {
B
Behdad Esfahbod 已提交
1940
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1941
    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
B
Behdad Esfahbod 已提交
1942 1943
  }

1944
  protected:
B
Behdad Esfahbod 已提交
1945
  HBUINT16	format;			/* Format identifier--format = 1 */
L
lancer 已提交
1946
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
1947 1948
		coverage;		/* Offset to Coverage table--from
					 * beginning of subtable */
L
lancer 已提交
1949
  Array16Of<EntryExitRecord>
B
Behdad Esfahbod 已提交
1950 1951
		entryExitRecord;	/* Array of EntryExit records--in
					 * Coverage Index order */
1952
  public:
1953
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
B
Behdad Esfahbod 已提交
1954 1955
};

B
Behdad Esfahbod 已提交
1956 1957
struct CursivePos
{
1958
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1959
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1960
  {
1961
    TRACE_DISPATCH (this, u.format);
1962
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1963
    switch (u.format) {
1964
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
1965
    default:return_trace (c->default_return_value ());
1966 1967 1968
    }
  }

1969
  protected:
B
Behdad Esfahbod 已提交
1970
  union {
B
Behdad Esfahbod 已提交
1971
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1972
  CursivePosFormat1	format1;
B
Behdad Esfahbod 已提交
1973 1974 1975 1976
  } u;
};


1977 1978 1979
typedef AnchorMatrix BaseArray;		/* base-major--
					 * in order of BaseCoverage Index--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
1980
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
1981

P
pssea 已提交
1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004
static void Markclass_closure_and_remap_indexes (const Coverage  &mark_coverage,
						 const MarkArray &mark_array,
						 const hb_set_t  &glyphset,
						 hb_map_t*        klass_mapping /* INOUT */)
{
  hb_set_t orig_classes;

  + hb_zip (mark_coverage, mark_array)
  | hb_filter (glyphset, hb_first)
  | hb_map (hb_second)
  | hb_map (&MarkRecord::get_class)
  | hb_sink (orig_classes)
  ;

  unsigned idx = 0;
  for (auto klass : orig_classes.iter ())
  {
    if (klass_mapping->has (klass)) continue;
    klass_mapping->set (klass, idx);
    idx++;
  }
}

B
Behdad Esfahbod 已提交
2005 2006
struct MarkBasePosFormat1
{
2007
  bool intersects (const hb_set_t *glyphs) const
P
pssea 已提交
2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043
  {
    return (this+markCoverage).intersects (glyphs) &&
	   (this+baseCoverage).intersects (glyphs);
  }

  void closure_lookups (hb_closure_lookups_context_t *c) const {}

  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    + hb_zip (this+markCoverage, this+markArray)
    | hb_filter (c->glyph_set, hb_first)
    | hb_map (hb_second)
    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
    ;

    hb_map_t klass_mapping;
    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);

    unsigned basecount = (this+baseArray).rows;
    auto base_iter =
    + hb_zip (this+baseCoverage, hb_range (basecount))
    | hb_filter (c->glyph_set, hb_first)
    | hb_map (hb_second)
    ;

    hb_sorted_vector_t<unsigned> base_indexes;
    for (const unsigned row : base_iter)
    {
      + hb_range ((unsigned) classCount)
      | hb_filter (klass_mapping)
      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
      | hb_sink (base_indexes)
      ;
    }
    (this+baseArray).collect_variation_indices (c, base_indexes.iter ());
  }
2044

2045
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
2046
  {
P
pssea 已提交
2047 2048
    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
    if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return;
2049 2050
  }

2051
  const Coverage &get_coverage () const { return this+markCoverage; }
2052

2053
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2054
  {
B
Behdad Esfahbod 已提交
2055
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
2056 2057
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
2058
    if (likely (mark_index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
2059

B
Behdad Esfahbod 已提交
2060
    /* Now we search backwards for a non-mark glyph */
2061
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
2062
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
2063
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
2064
    do {
B
Behdad Esfahbod 已提交
2065
      if (!skippy_iter.prev ()) return_trace (false);
2066 2067
      /* We only want to attach to the first of a MultipleSubst sequence.
       * https://github.com/harfbuzz/harfbuzz/issues/740
2068 2069 2070
       * Reject others...
       * ...but stop if we find a mark in the MultipleSubst sequence:
       * https://github.com/harfbuzz/harfbuzz/issues/1020 */
B
Behdad Esfahbod 已提交
2071
      if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
2072 2073
	  0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
	  (skippy_iter.idx == 0 ||
2074
	   _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
2075
	   _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
2076 2077 2078 2079
	   _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
	   _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
	   _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
	   ))
B
Behdad Esfahbod 已提交
2080
	break;
2081
      skippy_iter.reject ();
2082
    } while (true);
2083

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

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

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

2093
  bool subset (hb_subset_context_t *c) const
2094 2095
  {
    TRACE_SUBSET (this);
L
lancer 已提交
2096
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
P
pssea 已提交
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    out->format = format;

    hb_map_t klass_mapping;
    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);

    if (!klass_mapping.get_population ()) return_trace (false);
    out->classCount = klass_mapping.get_population ();

    auto mark_iter =
    + hb_zip (this+markCoverage, this+markArray)
    | hb_filter (glyphset, hb_first)
    ;

    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
    + mark_iter
    | hb_map (hb_first)
    | hb_map (glyph_map)
    | hb_sink (new_coverage)
    ;

    if (!out->markCoverage.serialize (c->serializer, out)
			  .serialize (c->serializer, new_coverage.iter ()))
      return_trace (false);

L
lancer 已提交
2125 2126 2127
    out->markArray.serialize_subset (c, markArray, this,
                                     (this+markCoverage).iter (),
                                     &klass_mapping);
P
pssea 已提交
2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155

    unsigned basecount = (this+baseArray).rows;
    auto base_iter =
    + hb_zip (this+baseCoverage, hb_range (basecount))
    | hb_filter (glyphset, hb_first)
    ;

    new_coverage.reset ();
    + base_iter
    | hb_map (hb_first)
    | hb_map (glyph_map)
    | hb_sink (new_coverage)
    ;

    if (!out->baseCoverage.serialize (c->serializer, out)
			  .serialize (c->serializer, new_coverage.iter ()))
      return_trace (false);

    hb_sorted_vector_t<unsigned> base_indexes;
    for (const unsigned row : + base_iter
			      | hb_map (hb_second))
    {
      + hb_range ((unsigned) classCount)
      | hb_filter (klass_mapping)
      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
      | hb_sink (base_indexes)
      ;
    }
L
lancer 已提交
2156 2157 2158 2159

    out->baseArray.serialize_subset (c, baseArray, this,
                                     base_iter.len (),
                                     base_indexes.iter ());
P
pssea 已提交
2160 2161

    return_trace (true);
2162 2163
  }

2164
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
2165
  {
B
Behdad Esfahbod 已提交
2166
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2167 2168 2169 2170 2171
    return_trace (c->check_struct (this) &&
		  markCoverage.sanitize (c, this) &&
		  baseCoverage.sanitize (c, this) &&
		  markArray.sanitize (c, this) &&
		  baseArray.sanitize (c, this, (unsigned int) classCount));
B
Behdad Esfahbod 已提交
2172 2173
  }

2174
  protected:
B
Behdad Esfahbod 已提交
2175
  HBUINT16	format;			/* Format identifier--format = 1 */
L
lancer 已提交
2176
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
2177
		markCoverage;		/* Offset to MarkCoverage table--from
B
Behdad Esfahbod 已提交
2178
					 * beginning of MarkBasePos subtable */
L
lancer 已提交
2179
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
2180
		baseCoverage;		/* Offset to BaseCoverage table--from
B
Behdad Esfahbod 已提交
2181
					 * beginning of MarkBasePos subtable */
B
Behdad Esfahbod 已提交
2182
  HBUINT16	classCount;		/* Number of classes defined for marks */
L
lancer 已提交
2183
  Offset16To<MarkArray>
B
Behdad Esfahbod 已提交
2184
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
2185
					 * beginning of MarkBasePos subtable */
L
lancer 已提交
2186
  Offset16To<BaseArray>
B
Behdad Esfahbod 已提交
2187
		baseArray;		/* Offset to BaseArray table--from
B
Behdad Esfahbod 已提交
2188
					 * beginning of MarkBasePos subtable */
2189 2190
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
2191 2192
};

B
Behdad Esfahbod 已提交
2193 2194
struct MarkBasePos
{
2195
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
2196
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2197
  {
2198
    TRACE_DISPATCH (this, u.format);
2199
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2200
    switch (u.format) {
2201
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
2202
    default:return_trace (c->default_return_value ());
2203 2204 2205
    }
  }

2206
  protected:
B
Behdad Esfahbod 已提交
2207
  union {
B
Behdad Esfahbod 已提交
2208
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
2209
  MarkBasePosFormat1	format1;
B
Behdad Esfahbod 已提交
2210 2211 2212 2213
  } u;
};


2214 2215 2216
typedef AnchorMatrix LigatureAttach;	/* component-major--
					 * in order of writing direction--,
					 * mark-minor--
B
Behdad Esfahbod 已提交
2217
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
2218

L
lancer 已提交
2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254
/* Array of LigatureAttach tables ordered by LigatureCoverage Index */
struct LigatureArray : List16OfOffset16To<LigatureAttach>
{
  template <typename Iterator,
	    hb_requires (hb_is_iterator (Iterator))>
  bool subset (hb_subset_context_t *c,
               Iterator		    coverage,
	       unsigned		    class_count,
	       const hb_map_t	   *klass_mapping) const
  {
    TRACE_SUBSET (this);
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();

    auto *out = c->serializer->start_embed (this);
    if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);

    for (const auto _ : + hb_zip (coverage, *this)
		  | hb_filter (glyphset, hb_first))
    {
      auto *matrix = out->serialize_append (c->serializer);
      if (unlikely (!matrix)) return_trace (false);

      const LigatureAttach& src = (this + _.second);
      auto indexes =
          + hb_range (src.rows * class_count)
          | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); })
          ;
      matrix->serialize_subset (c,
				_.second,
				this,
                                src.rows,
                                indexes);
    }
    return_trace (this->len);
  }
};
B
Behdad Esfahbod 已提交
2255

B
Behdad Esfahbod 已提交
2256 2257
struct MarkLigPosFormat1
{
2258
  bool intersects (const hb_set_t *glyphs) const
P
pssea 已提交
2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300
  {
    return (this+markCoverage).intersects (glyphs) &&
	   (this+ligatureCoverage).intersects (glyphs);
  }

  void closure_lookups (hb_closure_lookups_context_t *c) const {}

  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    + hb_zip (this+markCoverage, this+markArray)
    | hb_filter (c->glyph_set, hb_first)
    | hb_map (hb_second)
    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); })
    ;

    hb_map_t klass_mapping;
    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping);

    unsigned ligcount = (this+ligatureArray).len;
    auto lig_iter =
    + hb_zip (this+ligatureCoverage, hb_range (ligcount))
    | hb_filter (c->glyph_set, hb_first)
    | hb_map (hb_second)
    ;

    const LigatureArray& lig_array = this+ligatureArray;
    for (const unsigned i : lig_iter)
    {
      hb_sorted_vector_t<unsigned> lig_indexes;
      unsigned row_count = lig_array[i].rows;
      for (unsigned row : + hb_range (row_count))
      {
	+ hb_range ((unsigned) classCount)
	| hb_filter (klass_mapping)
	| hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
	| hb_sink (lig_indexes)
	;
      }

      lig_array[i].collect_variation_indices (c, lig_indexes.iter ());
    }
  }
2301

2302
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
2303
  {
P
pssea 已提交
2304 2305
    if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return;
    if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return;
2306 2307
  }

2308
  const Coverage &get_coverage () const { return this+markCoverage; }
2309

2310
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2311
  {
B
Behdad Esfahbod 已提交
2312
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
2313 2314
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
2315
    if (likely (mark_index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
2316

B
Behdad Esfahbod 已提交
2317
    /* Now we search backwards for a non-mark glyph */
2318
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
2319
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
2320
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
B
Behdad Esfahbod 已提交
2321
    if (!skippy_iter.prev ()) return_trace (false);
2322

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

B
Behdad Esfahbod 已提交
2326
    unsigned int j = skippy_iter.idx;
B
Behdad Esfahbod 已提交
2327
    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
B
Behdad Esfahbod 已提交
2328
    if (lig_index == NOT_COVERED) return_trace (false);
B
Behdad Esfahbod 已提交
2329 2330

    const LigatureArray& lig_array = this+ligatureArray;
2331
    const LigatureAttach& lig_attach = lig_array[lig_index];
2332 2333

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

B
Behdad Esfahbod 已提交
2337 2338 2339 2340
    /* We must now check whether the ligature ID of the current mark glyph
     * is identical to the ligature ID of the found ligature.  If yes, we
     * can directly use the component index.  If not, we attach the mark
     * glyph to the last component of the ligature. */
B
Behdad Esfahbod 已提交
2341
    unsigned int comp_index;
B
Behdad Esfahbod 已提交
2342 2343 2344
    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
B
Behdad Esfahbod 已提交
2345
    if (lig_id && lig_id == mark_id && mark_comp > 0)
2346
      comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
B
Behdad Esfahbod 已提交
2347
    else
B
Behdad Esfahbod 已提交
2348
      comp_index = comp_count - 1;
B
Behdad Esfahbod 已提交
2349

B
Behdad Esfahbod 已提交
2350
    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
B
Behdad Esfahbod 已提交
2351 2352
  }

2353
  bool subset (hb_subset_context_t *c) const
2354 2355
  {
    TRACE_SUBSET (this);
L
lancer 已提交
2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    out->format = format;

    hb_map_t klass_mapping;
    Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping);

    if (!klass_mapping.get_population ()) return_trace (false);
    out->classCount = klass_mapping.get_population ();

    auto mark_iter =
    + hb_zip (this+markCoverage, this+markArray)
    | hb_filter (glyphset, hb_first)
    ;

    auto new_mark_coverage =
    + mark_iter
    | hb_map_retains_sorting (hb_first)
    | hb_map_retains_sorting (glyph_map)
    ;

    if (!out->markCoverage.serialize (c->serializer, out)
			  .serialize (c->serializer, new_mark_coverage))
      return_trace (false);

    out->markArray.serialize_subset (c, markArray, this,
                                     (this+markCoverage).iter (),
                                     &klass_mapping);

    auto new_ligature_coverage =
    + hb_iter (this + ligatureCoverage)
    | hb_filter (glyphset)
    | hb_map_retains_sorting (glyph_map)
    ;

    if (!out->ligatureCoverage.serialize (c->serializer, out)
			      .serialize (c->serializer, new_ligature_coverage))
      return_trace (false);

    out->ligatureArray.serialize_subset (c, ligatureArray, this,
                                         hb_iter (this+ligatureCoverage), classCount, &klass_mapping);

    return_trace (true);
2402 2403
  }

2404
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
2405
  {
B
Behdad Esfahbod 已提交
2406
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2407 2408 2409 2410 2411
    return_trace (c->check_struct (this) &&
		  markCoverage.sanitize (c, this) &&
		  ligatureCoverage.sanitize (c, this) &&
		  markArray.sanitize (c, this) &&
		  ligatureArray.sanitize (c, this, (unsigned int) classCount));
B
Behdad Esfahbod 已提交
2412 2413
  }

2414
  protected:
B
Behdad Esfahbod 已提交
2415
  HBUINT16	format;			/* Format identifier--format = 1 */
L
lancer 已提交
2416
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
2417
		markCoverage;		/* Offset to Mark Coverage table--from
B
Behdad Esfahbod 已提交
2418
					 * beginning of MarkLigPos subtable */
L
lancer 已提交
2419
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
2420
		ligatureCoverage;	/* Offset to Ligature Coverage
B
Behdad Esfahbod 已提交
2421 2422
					 * table--from beginning of MarkLigPos
					 * subtable */
B
Behdad Esfahbod 已提交
2423
  HBUINT16	classCount;		/* Number of defined mark classes */
L
lancer 已提交
2424
  Offset16To<MarkArray>
B
Behdad Esfahbod 已提交
2425
		markArray;		/* Offset to MarkArray table--from
B
Behdad Esfahbod 已提交
2426
					 * beginning of MarkLigPos subtable */
L
lancer 已提交
2427
  Offset16To<LigatureArray>
B
Behdad Esfahbod 已提交
2428
		ligatureArray;		/* Offset to LigatureArray table--from
B
Behdad Esfahbod 已提交
2429
					 * beginning of MarkLigPos subtable */
2430 2431
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
2432 2433
};

L
lancer 已提交
2434

B
Behdad Esfahbod 已提交
2435 2436
struct MarkLigPos
{
2437
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
2438
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2439
  {
2440
    TRACE_DISPATCH (this, u.format);
2441
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2442
    switch (u.format) {
2443
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
2444
    default:return_trace (c->default_return_value ());
2445 2446 2447
    }
  }

2448
  protected:
B
Behdad Esfahbod 已提交
2449
  union {
B
Behdad Esfahbod 已提交
2450
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
2451
  MarkLigPosFormat1	format1;
B
Behdad Esfahbod 已提交
2452 2453 2454 2455
  } u;
};


2456 2457 2458 2459
typedef AnchorMatrix Mark2Array;	/* mark2-major--
					 * in order of Mark2Coverage Index--,
					 * mark1-minor--
					 * ordered by class--zero-based. */
B
Behdad Esfahbod 已提交
2460

B
Behdad Esfahbod 已提交
2461 2462
struct MarkMarkPosFormat1
{
2463
  bool intersects (const hb_set_t *glyphs) const
P
pssea 已提交
2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499
  {
    return (this+mark1Coverage).intersects (glyphs) &&
	   (this+mark2Coverage).intersects (glyphs);
  }

  void closure_lookups (hb_closure_lookups_context_t *c) const {}

  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    + hb_zip (this+mark1Coverage, this+mark1Array)
    | hb_filter (c->glyph_set, hb_first)
    | hb_map (hb_second)
    | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); })
    ;

    hb_map_t klass_mapping;
    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping);

    unsigned mark2_count = (this+mark2Array).rows;
    auto mark2_iter =
    + hb_zip (this+mark2Coverage, hb_range (mark2_count))
    | hb_filter (c->glyph_set, hb_first)
    | hb_map (hb_second)
    ;

    hb_sorted_vector_t<unsigned> mark2_indexes;
    for (const unsigned row : mark2_iter)
    {
      + hb_range ((unsigned) classCount)
      | hb_filter (klass_mapping)
      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
      | hb_sink (mark2_indexes)
      ;
    }
    (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ());
  }
2500

2501
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
2502
  {
P
pssea 已提交
2503 2504
    if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return;
    if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return;
2505 2506
  }

2507
  const Coverage &get_coverage () const { return this+mark1Coverage; }
2508

2509
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2510
  {
B
Behdad Esfahbod 已提交
2511
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
2512 2513
    hb_buffer_t *buffer = c->buffer;
    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
2514
    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
2515 2516

    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
2517
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
2518
    skippy_iter.reset (buffer->idx, 1);
B
Behdad Esfahbod 已提交
2519
    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
B
Behdad Esfahbod 已提交
2520
    if (!skippy_iter.prev ()) return_trace (false);
2521

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

B
Behdad Esfahbod 已提交
2524 2525
    unsigned int j = skippy_iter.idx;

B
Behdad Esfahbod 已提交
2526 2527 2528 2529
    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
2530

P
pssea 已提交
2531 2532
    if (likely (id1 == id2))
    {
2533 2534 2535
      if (id1 == 0) /* Marks belonging to the same base. */
	goto good;
      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
E
Ebrahim Byagowi 已提交
2536
	goto good;
P
pssea 已提交
2537 2538 2539
    }
    else
    {
2540 2541 2542 2543 2544 2545 2546
      /* If ligature ids don't match, it may be the case that one of the marks
       * itself is a ligature.  In which case match. */
      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
	goto good;
    }

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

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

B
Behdad Esfahbod 已提交
2553
    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
B
Behdad Esfahbod 已提交
2554 2555
  }

2556
  bool subset (hb_subset_context_t *c) const
2557 2558
  {
    TRACE_SUBSET (this);
L
lancer 已提交
2559
    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
P
pssea 已提交
2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587
    const hb_map_t &glyph_map = *c->plan->glyph_map;

    auto *out = c->serializer->start_embed (*this);
    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
    out->format = format;

    hb_map_t klass_mapping;
    Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping);

    if (!klass_mapping.get_population ()) return_trace (false);
    out->classCount = klass_mapping.get_population ();

    auto mark1_iter =
    + hb_zip (this+mark1Coverage, this+mark1Array)
    | hb_filter (glyphset, hb_first)
    ;

    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
    + mark1_iter
    | hb_map (hb_first)
    | hb_map (glyph_map)
    | hb_sink (new_coverage)
    ;

    if (!out->mark1Coverage.serialize (c->serializer, out)
			   .serialize (c->serializer, new_coverage.iter ()))
      return_trace (false);

L
lancer 已提交
2588 2589 2590
    out->mark1Array.serialize_subset (c, mark1Array, this,
                                      (this+mark1Coverage).iter (),
                                      &klass_mapping);
P
pssea 已提交
2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618

    unsigned mark2count = (this+mark2Array).rows;
    auto mark2_iter =
    + hb_zip (this+mark2Coverage, hb_range (mark2count))
    | hb_filter (glyphset, hb_first)
    ;

    new_coverage.reset ();
    + mark2_iter
    | hb_map (hb_first)
    | hb_map (glyph_map)
    | hb_sink (new_coverage)
    ;

    if (!out->mark2Coverage.serialize (c->serializer, out)
			   .serialize (c->serializer, new_coverage.iter ()))
      return_trace (false);

    hb_sorted_vector_t<unsigned> mark2_indexes;
    for (const unsigned row : + mark2_iter
			      | hb_map (hb_second))
    {
      + hb_range ((unsigned) classCount)
      | hb_filter (klass_mapping)
      | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; })
      | hb_sink (mark2_indexes)
      ;
    }
L
lancer 已提交
2619 2620

    out->mark2Array.serialize_subset (c, mark2Array, this, mark2_iter.len (), mark2_indexes.iter ());
P
pssea 已提交
2621 2622

    return_trace (true);
2623 2624
  }

2625
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
2626
  {
B
Behdad Esfahbod 已提交
2627
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2628 2629 2630 2631 2632
    return_trace (c->check_struct (this) &&
		  mark1Coverage.sanitize (c, this) &&
		  mark2Coverage.sanitize (c, this) &&
		  mark1Array.sanitize (c, this) &&
		  mark2Array.sanitize (c, this, (unsigned int) classCount));
B
Behdad Esfahbod 已提交
2633 2634
  }

2635
  protected:
B
Behdad Esfahbod 已提交
2636
  HBUINT16	format;			/* Format identifier--format = 1 */
L
lancer 已提交
2637
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
2638
		mark1Coverage;		/* Offset to Combining Mark1 Coverage
B
Behdad Esfahbod 已提交
2639 2640
					 * table--from beginning of MarkMarkPos
					 * subtable */
L
lancer 已提交
2641
  Offset16To<Coverage>
B
Behdad Esfahbod 已提交
2642
		mark2Coverage;		/* Offset to Combining Mark2 Coverage
B
Behdad Esfahbod 已提交
2643 2644
					 * table--from beginning of MarkMarkPos
					 * subtable */
B
Behdad Esfahbod 已提交
2645
  HBUINT16	classCount;		/* Number of defined mark classes */
L
lancer 已提交
2646
  Offset16To<MarkArray>
B
Behdad Esfahbod 已提交
2647 2648
		mark1Array;		/* Offset to Mark1Array table--from
					 * beginning of MarkMarkPos subtable */
L
lancer 已提交
2649
  Offset16To<Mark2Array>
B
Behdad Esfahbod 已提交
2650 2651
		mark2Array;		/* Offset to Mark2Array table--from
					 * beginning of MarkMarkPos subtable */
2652 2653
  public:
  DEFINE_SIZE_STATIC (12);
B
Behdad Esfahbod 已提交
2654 2655
};

B
Behdad Esfahbod 已提交
2656 2657
struct MarkMarkPos
{
2658
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
2659
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2660
  {
2661
    TRACE_DISPATCH (this, u.format);
2662
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2663
    switch (u.format) {
2664
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
2665
    default:return_trace (c->default_return_value ());
2666 2667 2668
    }
  }

2669
  protected:
B
Behdad Esfahbod 已提交
2670
  union {
B
Behdad Esfahbod 已提交
2671
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
2672
  MarkMarkPosFormat1	format1;
B
Behdad Esfahbod 已提交
2673 2674 2675 2676
  } u;
};


B
Minor  
Behdad Esfahbod 已提交
2677
struct ContextPos : Context {};
B
Behdad Esfahbod 已提交
2678

B
Minor  
Behdad Esfahbod 已提交
2679
struct ChainContextPos : ChainContext {};
B
Behdad Esfahbod 已提交
2680

B
Behdad Esfahbod 已提交
2681
struct ExtensionPos : Extension<ExtensionPos>
B
Behdad Esfahbod 已提交
2682
{
B
Behdad Esfahbod 已提交
2683
  typedef struct PosLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
2684 2685 2686
};


2687

B
Behdad Esfahbod 已提交
2688 2689 2690 2691 2692
/*
 * PosLookup
 */


B
Behdad Esfahbod 已提交
2693 2694
struct PosLookupSubTable
{
B
Behdad Esfahbod 已提交
2695
  friend struct Lookup;
B
Behdad Esfahbod 已提交
2696 2697
  friend struct PosLookup;

B
Behdad Esfahbod 已提交
2698
  enum Type {
2699 2700 2701 2702 2703 2704 2705 2706
    Single		= 1,
    Pair		= 2,
    Cursive		= 3,
    MarkBase		= 4,
    MarkLig		= 5,
    MarkMark		= 6,
    Context		= 7,
    ChainContext	= 8,
2707
    Extension		= 9
2708 2709
  };

2710
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
2711
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
2712
  {
2713
    TRACE_DISPATCH (this, lookup_type);
2714
    switch (lookup_type) {
2715 2716 2717 2718 2719 2720 2721 2722 2723
    case Single:		return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
    case Pair:			return_trace (u.pair.dispatch (c, hb_forward<Ts> (ds)...));
    case Cursive:		return_trace (u.cursive.dispatch (c, hb_forward<Ts> (ds)...));
    case MarkBase:		return_trace (u.markBase.dispatch (c, hb_forward<Ts> (ds)...));
    case MarkLig:		return_trace (u.markLig.dispatch (c, hb_forward<Ts> (ds)...));
    case MarkMark:		return_trace (u.markMark.dispatch (c, hb_forward<Ts> (ds)...));
    case Context:		return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
    case ChainContext:		return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
    case Extension:		return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
2724
    default:			return_trace (c->default_return_value ());
2725
    }
2726 2727
  }

P
pssea 已提交
2728 2729 2730 2731 2732 2733
  bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c, lookup_type);
  }

2734
  protected:
B
Behdad Esfahbod 已提交
2735
  union {
B
Behdad Esfahbod 已提交
2736 2737 2738 2739 2740 2741
  SinglePos		single;
  PairPos		pair;
  CursivePos		cursive;
  MarkBasePos		markBase;
  MarkLigPos		markLig;
  MarkMarkPos		markMark;
2742
  ContextPos		context;
B
Behdad Esfahbod 已提交
2743 2744
  ChainContextPos	chainContext;
  ExtensionPos		extension;
B
Behdad Esfahbod 已提交
2745
  } u;
B
Behdad Esfahbod 已提交
2746
  public:
B
Behdad Esfahbod 已提交
2747
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
2748 2749 2750
};


B
Behdad Esfahbod 已提交
2751 2752
struct PosLookup : Lookup
{
B
Behdad Esfahbod 已提交
2753 2754
  typedef struct PosLookupSubTable SubTable;

2755
  const SubTable& get_subtable (unsigned int i) const
B
Behdad Esfahbod 已提交
2756
  { return Lookup::get_subtable<SubTable> (i); }
B
Behdad Esfahbod 已提交
2757

2758
  bool is_reverse () const
B
Behdad Esfahbod 已提交
2759 2760 2761 2762
  {
    return false;
  }

2763
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2764 2765
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
2766
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
2767 2768
  }

2769
  bool intersects (const hb_set_t *glyphs) const
2770 2771 2772 2773 2774
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

2775
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
2776
  { return dispatch (c); }
2777

P
pssea 已提交
2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794
  hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
  {
    if (c->is_lookup_visited (this_index))
      return hb_closure_lookups_context_t::default_return_value ();

    c->set_lookup_visited (this_index);
    if (!intersects (c->glyphs))
    {
      c->set_lookup_inactive (this_index);
      return hb_closure_lookups_context_t::default_return_value ();
    }
    c->set_recurse_func (dispatch_closure_lookups_recurse_func);

    hb_closure_lookups_context_t::return_t ret = dispatch (c);
    return ret;
  }

B
Behdad Esfahbod 已提交
2795
  template <typename set_t>
P
pssea 已提交
2796
  void collect_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
2797
  {
P
pssea 已提交
2798
    hb_collect_coverage_context_t<set_t> c (glyphs);
2799
    dispatch (&c);
B
Behdad Esfahbod 已提交
2800 2801
  }

P
pssea 已提交
2802
  static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
2803

B
Behdad Esfahbod 已提交
2804
  template <typename context_t>
2805
  static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
2806

P
pssea 已提交
2807 2808
  HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index);

2809
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
2810
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2811
  { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
B
Behdad Esfahbod 已提交
2812

2813
  bool subset (hb_subset_context_t *c) const
2814 2815
  { return Lookup::subset<SubTable> (c); }

2816
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
2817
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
2818 2819 2820
};

/*
2821 2822
 * GPOS -- Glyph Positioning
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
B
Behdad Esfahbod 已提交
2823 2824
 */

B
Behdad Esfahbod 已提交
2825 2826
struct GPOS : GSUBGPOS
{
2827
  static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
2828

2829
  const PosLookup& get_lookup (unsigned int i) const
P
pssea 已提交
2830
  { return static_cast<const PosLookup &> (GSUBGPOS::get_lookup (i)); }
B
Behdad Esfahbod 已提交
2831

2832
  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
2833 2834
  static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
  static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
B
Behdad Esfahbod 已提交
2835

2836
  bool subset (hb_subset_context_t *c) const
P
pssea 已提交
2837
  {
L
lancer 已提交
2838
    hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
P
pssea 已提交
2839 2840
    return GSUBGPOS::subset<PosLookup> (&l);
  }
2841

2842
  bool sanitize (hb_sanitize_context_t *c) const
2843
  { return GSUBGPOS::sanitize<PosLookup> (c); }
B
WIP  
Behdad Esfahbod 已提交
2844

P
pssea 已提交
2845
  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
2846 2847
				   hb_face_t *face) const;

P
pssea 已提交
2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862
  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
  {
    for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++)
    {
      if (!c->gpos_lookups->has (i)) continue;
      const PosLookup &l = get_lookup (i);
      l.dispatch (c);
    }
  }

  void closure_lookups (hb_face_t      *face,
			const hb_set_t *glyphs,
			hb_set_t       *lookup_indexes /* IN/OUT */) const
  { GSUBGPOS::closure_lookups<PosLookup> (face, glyphs, lookup_indexes); }

B
WIP  
Behdad Esfahbod 已提交
2863
  typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
B
Behdad Esfahbod 已提交
2864 2865
};

B
Behdad Esfahbod 已提交
2866

2867 2868 2869
static void
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
{
2870 2871
  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
2872 2873
    return;

2874
  pos[i].attach_chain() = 0;
2875

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

2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888
  /* Stop if we see new parent in the chain. */
  if (j == new_parent)
    return;

  reverse_cursive_minor_offset (pos, j, direction, new_parent);

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

2889 2890
  pos[j].attach_chain() = -chain;
  pos[j].attach_type() = type;
2891
}
B
Behdad Esfahbod 已提交
2892
static void
2893 2894 2895 2896
propagate_attachment_offsets (hb_glyph_position_t *pos,
			      unsigned int len,
			      unsigned int i,
			      hb_direction_t direction)
B
Behdad Esfahbod 已提交
2897
{
2898 2899
  /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
   * offset of glyph they are attached to. */
2900
  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
2901
  if (likely (!chain))
B
Behdad Esfahbod 已提交
2902
    return;
B
Behdad Esfahbod 已提交
2903

2904 2905
  pos[i].attach_chain() = 0;

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

2908 2909
  if (unlikely (j >= len))
    return;
2910

2911
  propagate_attachment_offsets (pos, len, j, direction);
2912

2913
  assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
B
Behdad Esfahbod 已提交
2914

2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925
  if (type & ATTACH_TYPE_CURSIVE)
  {
    if (HB_DIRECTION_IS_HORIZONTAL (direction))
      pos[i].y_offset += pos[j].y_offset;
    else
      pos[i].x_offset += pos[j].x_offset;
  }
  else /*if (type & ATTACH_TYPE_MARK)*/
  {
    pos[i].x_offset += pos[j].x_offset;
    pos[i].y_offset += pos[j].y_offset;
2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937

    assert (j < i);
    if (HB_DIRECTION_IS_FORWARD (direction))
      for (unsigned int k = j; k < i; k++) {
	pos[i].x_offset -= pos[k].x_advance;
	pos[i].y_offset -= pos[k].y_advance;
      }
    else
      for (unsigned int k = j + 1; k < i + 1; k++) {
	pos[i].x_offset += pos[k].x_advance;
	pos[i].y_offset += pos[k].y_advance;
      }
2938
  }
B
Behdad Esfahbod 已提交
2939 2940
}

B
Behdad Esfahbod 已提交
2941
void
2942
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
2943
{
2944 2945
  unsigned int count = buffer->len;
  for (unsigned int i = 0; i < count; i++)
2946
    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
B
Behdad Esfahbod 已提交
2947 2948
}

B
Behdad Esfahbod 已提交
2949
void
2950
GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
2951 2952 2953 2954 2955 2956
{
  //_hb_buffer_assert_gsubgpos_vars (buffer);
}

void
GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
2957
{
2958 2959
  _hb_buffer_assert_gsubgpos_vars (buffer);

2960 2961
  unsigned int len;
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
B
Behdad Esfahbod 已提交
2962 2963 2964
  hb_direction_t direction = buffer->props.direction;

  /* Handle attachments */
2965 2966
  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
    for (unsigned int i = 0; i < len; i++)
2967
      propagate_attachment_offsets (pos, len, i, direction);
B
Behdad Esfahbod 已提交
2968 2969
}

B
Behdad Esfahbod 已提交
2970

B
Behdad Esfahbod 已提交
2971 2972 2973
struct GPOS_accelerator_t : GPOS::accelerator_t {};


B
Behdad Esfahbod 已提交
2974 2975
/* Out-of-class implementation for methods recursing */

2976
#ifndef HB_NO_OT_LAYOUT
2977
template <typename context_t>
P
pssea 已提交
2978
/*static*/ typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
2979
{
B
Behdad Esfahbod 已提交
2980
  const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
2981
  return l.dispatch (c);
2982
}
P
pssea 已提交
2983 2984 2985 2986 2987 2988 2989 2990

/*static*/ inline hb_closure_lookups_context_t::return_t PosLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
{
  const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (this_index);
  return l.closure_lookups (c, this_index);
}

/*static*/ bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
2991
{
B
Behdad Esfahbod 已提交
2992
  const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index);
2993
  unsigned int saved_lookup_props = c->lookup_props;
2994 2995 2996
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
2997
  bool ret = l.dispatch (c);
2998
  c->set_lookup_index (saved_lookup_index);
2999
  c->set_lookup_props (saved_lookup_props);
3000
  return ret;
B
Behdad Esfahbod 已提交
3001
}
3002
#endif
B
Behdad Esfahbod 已提交
3003 3004


B
Behdad Esfahbod 已提交
3005
} /* namespace OT */
3006

B
Behdad Esfahbod 已提交
3007

3008
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */