Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3
 * Copyright © 2010,2012,2013  Google, Inc.
4
 *
5
 *  This is part of HarfBuzz, a text shaping library.
6
 *
7
 * Permission is hereby granted, without written agreement and without
8
 * license or royalty fees, to use, copy, modify, and distribute this
9
 * software and its documentation for any purpose, provided that the
10
 * above copyright notice and the following two paragraphs appear in
11
 * all copies of this software.
12
 *
13
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17
 * DAMAGE.
18
 *
19
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24
 *
25
 * Red Hat Author(s): Behdad Esfahbod
26
 * Google Author(s): Behdad Esfahbod
27
 */
28
29
#ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
30
#define HB_OT_LAYOUT_GPOS_TABLE_HH
31
32
#include "hb-ot-layout-gsubgpos.hh"
33
34
35
namespace OT {
36
37
38
/* buffer **position** var allocations */
39
0
#define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
40
0
#define attach_type() var.u8[2] /* attachment type */
41
/* Note! if attach_chain() is zero, the value of attach_type() is irrelevant. */
42
43
enum attach_type_t {
44
  ATTACH_TYPE_NONE  = 0X00,
45
46
  /* Each attachment should be either a mark or a cursive; can't be both. */
47
  ATTACH_TYPE_MARK  = 0X01,
48
  ATTACH_TYPE_CURSIVE = 0X02,
49
};
50
51
52
/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
53
54
typedef HBUINT16 Value;
55
56
typedef Value ValueRecord[VAR];
57
58
struct ValueFormat : HBUINT16
59
{
60
  enum Flags {
61
    xPlacement  = 0x0001u,  /* Includes horizontal adjustment for placement */
62
    yPlacement  = 0x0002u,  /* Includes vertical adjustment for placement */
63
    xAdvance  = 0x0004u,  /* Includes horizontal adjustment for advance */
64
    yAdvance  = 0x0008u,  /* Includes vertical adjustment for advance */
65
    xPlaDevice  = 0x0010u,  /* Includes horizontal Device table for placement */
66
    yPlaDevice  = 0x0020u,  /* Includes vertical Device table for placement */
67
    xAdvDevice  = 0x0040u,  /* Includes horizontal Device table for advance */
68
    yAdvDevice  = 0x0080u,  /* Includes vertical Device table for advance */
69
    ignored = 0x0F00u,  /* Was used in TrueType Open for MM fonts */
70
    reserved  = 0xF000u,  /* For future use */
71
72
    devices = 0x00F0u /* Mask for having any Device table */
73
  };
74
75
/* All fields are options.  Only those available advance the value pointer. */
76
#if 0
77
  HBINT16   xPlacement;   /* Horizontal adjustment for
78
           * placement--in design units */
79
  HBINT16   yPlacement;   /* Vertical adjustment for
80
           * placement--in design units */
81
  HBINT16   xAdvance;   /* Horizontal adjustment for
82
           * advance--in design units (only used
83
           * for horizontal writing) */
84
  HBINT16   yAdvance;   /* Vertical adjustment for advance--in
85
           * design units (only used for vertical
86
           * writing) */
87
  Offset  xPlaDevice;   /* Offset to Device table for
88
           * horizontal placement--measured from
89
           * beginning of PosTable (may be NULL) */
90
  Offset  yPlaDevice;   /* Offset to Device table for vertical
91
           * placement--measured from beginning
92
           * of PosTable (may be NULL) */
93
  Offset  xAdvDevice;   /* Offset to Device table for
94
           * horizontal advance--measured from
95
           * beginning of PosTable (may be NULL) */
96
  Offset  yAdvDevice;   /* Offset to Device table for vertical
97
           * advance--measured from beginning of
98
           * PosTable (may be NULL) */
99
#endif
100
101
  inline unsigned int get_len (void) const
102
0
  { return hb_popcount ((unsigned int) *this); }
103
  inline unsigned int get_size (void) const
104
0
  { return get_len () * Value::static_size; }
105
106
  void apply_value (hb_ot_apply_context_t   *c,
107
        const void           *base,
108
        const Value          *values,
109
        hb_glyph_position_t  &glyph_pos) const
110
0
  {
111
0
    unsigned int format = *this;
112
0
    if (!format) return;
113
0
114
0
    hb_font_t *font = c->font;
115
0
    hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction);
116
0
117
0
    if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++));
118
0
    if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++));
119
0
    if (format & xAdvance) {
120
0
      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
121
0
      values++;
122
0
    }
123
0
    /* y_advance values grow downward but font-space grows upward, hence negation */
124
0
    if (format & yAdvance) {
125
0
      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
126
0
      values++;
127
0
    }
128
0
129
0
    if (!has_device ()) return;
130
0
131
0
    bool use_x_device = font->x_ppem || font->num_coords;
132
0
    bool use_y_device = font->y_ppem || font->num_coords;
133
0
134
0
    if (!use_x_device && !use_y_device) return;
135
0
136
0
    const VariationStore &store = c->var_store;
137
0
138
0
    /* pixel -> fractional pixel */
139
0
    if (format & xPlaDevice) {
140
0
      if (use_x_device) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font, store);
141
0
      values++;
142
0
    }
143
0
    if (format & yPlaDevice) {
144
0
      if (use_y_device) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font, store);
145
0
      values++;
146
0
    }
147
0
    if (format & xAdvDevice) {
148
0
      if (horizontal && use_x_device) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font, store);
149
0
      values++;
150
0
    }
151
0
    if (format & yAdvDevice) {
152
0
      /* y_advance values grow downward but font-space grows upward, hence negation */
153
0
      if (!horizontal && use_y_device) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font, store);
154
0
      values++;
155
0
    }
156
0
  }
157
158
  private:
159
  inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
160
0
  {
161
0
    unsigned int format = *this;
162
0
163
0
    if (format & xPlacement) values++;
164
0
    if (format & yPlacement) values++;
165
0
    if (format & xAdvance)   values++;
166
0
    if (format & yAdvance)   values++;
167
0
168
0
    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
169
0
    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
170
0
    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
171
0
    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
172
0
173
0
    return true;
174
0
  }
175
176
  static inline OffsetTo<Device>& get_device (Value* value)
177
0
  { return *CastP<OffsetTo<Device> > (value); }
178
  static inline const OffsetTo<Device>& get_device (const Value* value)
179
0
  { return *CastP<OffsetTo<Device> > (value); }
180
181
  static inline const HBINT16& get_short (const Value* value)
182
0
  { return *CastP<HBINT16> (value); }
183
184
  public:
185
186
0
  inline bool has_device (void) const {
187
0
    unsigned int format = *this;
188
0
    return (format & devices) != 0;
189
0
  }
190
191
  inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
192
0
  {
193
0
    TRACE_SANITIZE (this);
194
0
    return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
195
0
  }
196
197
  inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
198
0
  {
199
0
    TRACE_SANITIZE (this);
200
0
    unsigned int len = get_len ();
201
0
202
0
    if (!c->check_array (values, get_size (), count)) return_trace (false);
203
0
204
0
    if (!has_device ()) return_trace (true);
205
0
206
0
    for (unsigned int i = 0; i < count; i++) {
207
0
      if (!sanitize_value_devices (c, base, values))
208
0
        return_trace (false);
209
0
      values += len;
210
0
    }
211
0
212
0
    return_trace (true);
213
0
  }
214
215
  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
216
  inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
217
0
  {
218
0
    TRACE_SANITIZE (this);
219
0
220
0
    if (!has_device ()) return_trace (true);
221
0
222
0
    for (unsigned int i = 0; i < count; i++) {
223
0
      if (!sanitize_value_devices (c, base, values))
224
0
        return_trace (false);
225
0
      values += stride;
226
0
    }
227
0
228
0
    return_trace (true);
229
0
  }
230
};
231
232
233
struct AnchorFormat1
234
{
235
  inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
236
        float *x, float *y) const
237
0
  {
238
0
    hb_font_t *font = c->font;
239
0
    *x = font->em_fscale_x (xCoordinate);
240
0
    *y = font->em_fscale_y (yCoordinate);
241
0
  }
242
243
  inline bool sanitize (hb_sanitize_context_t *c) const
244
0
  {
245
0
    TRACE_SANITIZE (this);
246
0
    return_trace (c->check_struct (this));
247
0
  }
248
249
  protected:
250
  HBUINT16  format;     /* Format identifier--format = 1 */
251
  FWORD   xCoordinate;    /* Horizontal value--in design units */
252
  FWORD   yCoordinate;    /* Vertical value--in design units */
253
  public:
254
  DEFINE_SIZE_STATIC (6);
255
};
256
257
struct AnchorFormat2
258
{
259
  inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
260
        float *x, float *y) const
261
0
  {
262
0
    hb_font_t *font = c->font;
263
0
    unsigned int x_ppem = font->x_ppem;
264
0
    unsigned int y_ppem = font->y_ppem;
265
0
    hb_position_t cx = 0, cy = 0;
266
0
    hb_bool_t ret;
267
0
268
0
    ret = (x_ppem || y_ppem) &&
269
0
     font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
270
0
    *x = ret && x_ppem ? cx : font->em_fscale_x (xCoordinate);
271
0
    *y = ret && y_ppem ? cy : font->em_fscale_y (yCoordinate);
272
0
  }
273
274
  inline bool sanitize (hb_sanitize_context_t *c) const
275
0
  {
276
0
    TRACE_SANITIZE (this);
277
0
    return_trace (c->check_struct (this));
278
0
  }
279
280
  protected:
281
  HBUINT16  format;     /* Format identifier--format = 2 */
282
  FWORD   xCoordinate;    /* Horizontal value--in design units */
283
  FWORD   yCoordinate;    /* Vertical value--in design units */
284
  HBUINT16  anchorPoint;    /* Index to glyph contour point */
285
  public:
286
  DEFINE_SIZE_STATIC (8);
287
};
288
289
struct AnchorFormat3
290
{
291
  inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id HB_UNUSED,
292
        float *x, float *y) const
293
0
  {
294
0
    hb_font_t *font = c->font;
295
0
    *x = font->em_fscale_x (xCoordinate);
296
0
    *y = font->em_fscale_y (yCoordinate);
297
0
298
0
    if (font->x_ppem || font->num_coords)
299
0
      *x += (this+xDeviceTable).get_x_delta (font, c->var_store);
300
0
    if (font->y_ppem || font->num_coords)
301
0
      *y += (this+yDeviceTable).get_y_delta (font, c->var_store);
302
0
  }
303
304
  inline bool sanitize (hb_sanitize_context_t *c) const
305
0
  {
306
0
    TRACE_SANITIZE (this);
307
0
    return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
308
0
  }
309
310
  protected:
311
  HBUINT16  format;     /* Format identifier--format = 3 */
312
  FWORD   xCoordinate;    /* Horizontal value--in design units */
313
  FWORD   yCoordinate;    /* Vertical value--in design units */
314
  OffsetTo<Device>
315
    xDeviceTable;   /* Offset to Device table for X
316
           * coordinate-- from beginning of
317
           * Anchor table (may be NULL) */
318
  OffsetTo<Device>
319
    yDeviceTable;   /* Offset to Device table for Y
320
           * coordinate-- from beginning of
321
           * Anchor table (may be NULL) */
322
  public:
323
  DEFINE_SIZE_STATIC (10);
324
};
325
326
struct Anchor
327
{
328
  inline void get_anchor (hb_ot_apply_context_t *c, hb_codepoint_t glyph_id,
329
        float *x, float *y) const
330
  {
331
    *x = *y = 0;
332
    switch (u.format) {
333
    case 1: u.format1.get_anchor (c, glyph_id, x, y); return;
334
    case 2: u.format2.get_anchor (c, glyph_id, x, y); return;
335
    case 3: u.format3.get_anchor (c, glyph_id, x, y); return;
336
    default:                return;
337
    }
338
  }
339
340
  inline bool sanitize (hb_sanitize_context_t *c) const
341
0
  {
342
0
    TRACE_SANITIZE (this);
343
0
    if (!u.format.sanitize (c)) return_trace (false);
344
0
    switch (u.format) {
345
0
    case 1: return_trace (u.format1.sanitize (c));
346
0
    case 2: return_trace (u.format2.sanitize (c));
347
0
    case 3: return_trace (u.format3.sanitize (c));
348
0
    default:return_trace (true);
349
0
    }
350
0
  }
351
352
  protected:
353
  union {
354
  HBUINT16    format;   /* Format identifier */
355
  AnchorFormat1   format1;
356
  AnchorFormat2   format2;
357
  AnchorFormat3   format3;
358
  } u;
359
  public:
360
  DEFINE_SIZE_UNION (2, format);
361
};
362
363
364
struct AnchorMatrix
365
{
366
0
  inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
367
0
    *found = false;
368
0
    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
369
0
    *found = !matrixZ[row * cols + col].is_null ();
370
0
    return this+matrixZ[row * cols + col];
371
0
  }
372
373
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
374
0
  {
375
0
    TRACE_SANITIZE (this);
376
0
    if (!c->check_struct (this)) return_trace (false);
377
0
    if (unlikely (hb_unsigned_mul_overflows (rows, cols))) return_trace (false);
378
0
    unsigned int count = rows * cols;
379
0
    if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
380
0
    for (unsigned int i = 0; i < count; i++)
381
0
      if (!matrixZ[i].sanitize (c, this)) return_trace (false);
382
0
    return_trace (true);
383
0
  }
384
385
  HBUINT16  rows;     /* Number of rows */
386
  protected:
387
  OffsetTo<Anchor>
388
    matrixZ[VAR];   /* Matrix of offsets to Anchor tables--
389
           * from beginning of AnchorMatrix table */
390
  public:
391
  DEFINE_SIZE_ARRAY (2, matrixZ);
392
};
393
394
395
struct MarkRecord
396
{
397
  friend struct MarkArray;
398
399
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
400
0
  {
401
0
    TRACE_SANITIZE (this);
402
0
    return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
403
0
  }
404
405
  protected:
406
  HBUINT16  klass;      /* Class defined for this mark */
407
  OffsetTo<Anchor>
408
    markAnchor;   /* Offset to Anchor table--from
409
           * beginning of MarkArray table */
410
  public:
411
  DEFINE_SIZE_STATIC (4);
412
};
413
414
struct MarkArray : ArrayOf<MarkRecord>  /* Array of MarkRecords--in Coverage order */
415
{
416
  inline bool apply (hb_ot_apply_context_t *c,
417
         unsigned int mark_index, unsigned int glyph_index,
418
         const AnchorMatrix &anchors, unsigned int class_count,
419
         unsigned int glyph_pos) const
420
0
  {
421
0
    TRACE_APPLY (this);
422
0
    hb_buffer_t *buffer = c->buffer;
423
0
    const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
424
0
    unsigned int mark_class = record.klass;
425
0
426
0
    const Anchor& mark_anchor = this + record.markAnchor;
427
0
    bool found;
428
0
    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
429
0
    /* If this subtable doesn't have an anchor for this base and this class,
430
0
     * return false such that the subsequent subtables have a chance at it. */
431
0
    if (unlikely (!found)) return_trace (false);
432
0
433
0
    float mark_x, mark_y, base_x, base_y;
434
0
435
0
    buffer->unsafe_to_break (glyph_pos, buffer->idx);
436
0
    mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y);
437
0
    glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
438
0
439
0
    hb_glyph_position_t &o = buffer->cur_pos();
440
0
    o.x_offset = round (base_x - mark_x);
441
0
    o.y_offset = round (base_y - mark_y);
442
0
    o.attach_type() = ATTACH_TYPE_MARK;
443
0
    o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
444
0
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
445
0
446
0
    buffer->idx++;
447
0
    return_trace (true);
448
0
  }
449
450
  inline bool sanitize (hb_sanitize_context_t *c) const
451
0
  {
452
0
    TRACE_SANITIZE (this);
453
0
    return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
454
0
  }
455
};
456
457
458
/* Lookups */
459
460
struct SinglePosFormat1
461
{
462
  inline bool intersects (const hb_set_t *glyphs) const
463
0
  { return (this+coverage).intersects (glyphs); }
464
465
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
466
0
  {
467
0
    TRACE_COLLECT_GLYPHS (this);
468
0
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
469
0
  }
470
471
  inline const Coverage &get_coverage (void) const
472
0
  { return this+coverage; }
473
474
  inline bool apply (hb_ot_apply_context_t *c) const
475
0
  {
476
0
    TRACE_APPLY (this);
477
0
    hb_buffer_t *buffer = c->buffer;
478
0
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
479
0
    if (likely (index == NOT_COVERED)) return_trace (false);
480
0
481
0
    valueFormat.apply_value (c, this, values, buffer->cur_pos());
482
0
483
0
    buffer->idx++;
484
0
    return_trace (true);
485
0
  }
486
487
  inline bool subset (hb_subset_context_t *c) const
488
0
  {
489
0
    TRACE_SUBSET (this);
490
0
    // TODO(subset)
491
0
    return_trace (false);
492
0
  }
493
494
  inline bool sanitize (hb_sanitize_context_t *c) const
495
0
  {
496
0
    TRACE_SANITIZE (this);
497
0
    return_trace (c->check_struct (this) &&
498
0
      coverage.sanitize (c, this) &&
499
0
      valueFormat.sanitize_value (c, this, values));
500
0
  }
501
502
  protected:
503
  HBUINT16  format;     /* Format identifier--format = 1 */
504
  OffsetTo<Coverage>
505
    coverage;   /* Offset to Coverage table--from
506
           * beginning of subtable */
507
  ValueFormat valueFormat;    /* Defines the types of data in the
508
           * ValueRecord */
509
  ValueRecord values;     /* Defines positioning
510
           * value(s)--applied to all glyphs in
511
           * the Coverage table */
512
  public:
513
  DEFINE_SIZE_ARRAY (6, values);
514
};
515
516
struct SinglePosFormat2
517
{
518
  inline bool intersects (const hb_set_t *glyphs) const
519
0
  { return (this+coverage).intersects (glyphs); }
520
521
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
522
0
  {
523
0
    TRACE_COLLECT_GLYPHS (this);
524
0
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
525
0
  }
526
527
  inline const Coverage &get_coverage (void) const
528
0
  { return this+coverage; }
529
530
  inline bool apply (hb_ot_apply_context_t *c) const
531
0
  {
532
0
    TRACE_APPLY (this);
533
0
    hb_buffer_t *buffer = c->buffer;
534
0
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
535
0
    if (likely (index == NOT_COVERED)) return_trace (false);
536
0
537
0
    if (likely (index >= valueCount)) return_trace (false);
538
0
539
0
    valueFormat.apply_value (c, this,
540
0
           &values[index * valueFormat.get_len ()],
541
0
           buffer->cur_pos());
542
0
543
0
    buffer->idx++;
544
0
    return_trace (true);
545
0
  }
546
547
  inline bool subset (hb_subset_context_t *c) const
548
0
  {
549
0
    TRACE_SUBSET (this);
550
0
    // TODO(subset)
551
0
    return_trace (false);
552
0
  }
553
554
  inline bool sanitize (hb_sanitize_context_t *c) const
555
0
  {
556
0
    TRACE_SANITIZE (this);
557
0
    return_trace (c->check_struct (this) &&
558
0
      coverage.sanitize (c, this) &&
559
0
      valueFormat.sanitize_values (c, this, values, valueCount));
560
0
  }
561
562
  protected:
563
  HBUINT16  format;     /* Format identifier--format = 2 */
564
  OffsetTo<Coverage>
565
    coverage;   /* Offset to Coverage table--from
566
           * beginning of subtable */
567
  ValueFormat valueFormat;    /* Defines the types of data in the
568
           * ValueRecord */
569
  HBUINT16  valueCount;   /* Number of ValueRecords */
570
  ValueRecord values;     /* Array of ValueRecords--positioning
571
           * values applied to glyphs */
572
  public:
573
  DEFINE_SIZE_ARRAY (8, values);
574
};
575
576
struct SinglePos
577
{
578
  template <typename context_t>
579
  inline typename context_t::return_t dispatch (context_t *c) const
580
0
  {
581
0
    TRACE_DISPATCH (this, u.format);
582
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
583
0
    switch (u.format) {
584
0
    case 1: return_trace (c->dispatch (u.format1));
585
0
    case 2: return_trace (c->dispatch (u.format2));
586
0
    default:return_trace (c->default_return_value ());
587
0
    }
588
0
  }
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::SinglePos::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::SinglePos::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >::return_t OT::SinglePos::dispatch<OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > > >(OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::SinglePos::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: hb_get_subtables_context_t::return_t OT::SinglePos::dispatch<hb_get_subtables_context_t>(hb_get_subtables_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::SinglePos::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::SinglePos::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
589
590
  protected:
591
  union {
592
  HBUINT16    format;   /* Format identifier */
593
  SinglePosFormat1  format1;
594
  SinglePosFormat2  format2;
595
  } u;
596
};
597
598
599
struct PairValueRecord
600
{
601
  friend struct PairSet;
602
603
  protected:
604
  GlyphID secondGlyph;    /* GlyphID of second glyph in the
605
           * pair--first glyph is listed in the
606
           * Coverage table */
607
  ValueRecord values;     /* Positioning data for the first glyph
608
           * followed by for second glyph */
609
  public:
610
  DEFINE_SIZE_ARRAY (2, values);
611
};
612
613
struct PairSet
614
{
615
  friend struct PairPosFormat1;
616
617
  inline bool intersects (const hb_set_t *glyphs,
618
        const ValueFormat *valueFormats) const
619
0
  {
620
0
    unsigned int len1 = valueFormats[0].get_len ();
621
0
    unsigned int len2 = valueFormats[1].get_len ();
622
0
    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
623
0
624
0
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
625
0
    unsigned int count = len;
626
0
    for (unsigned int i = 0; i < count; i++)
627
0
    {
628
0
      if (glyphs->has (record->secondGlyph))
629
0
        return true;
630
0
      record = &StructAtOffset<const PairValueRecord> (record, record_size);
631
0
    }
632
0
    return false;
633
0
  }
634
635
  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
636
            const ValueFormat *valueFormats) const
637
0
  {
638
0
    TRACE_COLLECT_GLYPHS (this);
639
0
    unsigned int len1 = valueFormats[0].get_len ();
640
0
    unsigned int len2 = valueFormats[1].get_len ();
641
0
    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
642
0
643
0
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
644
0
    c->input->add_array (&record->secondGlyph, len, record_size);
645
0
  }
646
647
  inline bool apply (hb_ot_apply_context_t *c,
648
         const ValueFormat *valueFormats,
649
         unsigned int pos) const
650
0
  {
651
0
    TRACE_APPLY (this);
652
0
    hb_buffer_t *buffer = c->buffer;
653
0
    unsigned int len1 = valueFormats[0].get_len ();
654
0
    unsigned int len2 = valueFormats[1].get_len ();
655
0
    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
656
0
657
0
    const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
658
0
    unsigned int count = len;
659
0
660
0
    /* Hand-coded bsearch. */
661
0
    if (unlikely (!count))
662
0
      return_trace (false);
663
0
    hb_codepoint_t x = buffer->info[pos].codepoint;
664
0
    int min = 0, max = (int) count - 1;
665
0
    while (min <= max)
666
0
    {
667
0
      int mid = (min + max) / 2;
668
0
      const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
669
0
      hb_codepoint_t mid_x = record->secondGlyph;
670
0
      if (x < mid_x)
671
0
        max = mid - 1;
672
0
      else if (x > mid_x)
673
0
        min = mid + 1;
674
0
      else
675
0
      {
676
0
        buffer->unsafe_to_break (buffer->idx, pos + 1);
677
0
  valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos());
678
0
  valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]);
679
0
  if (len2)
680
0
    pos++;
681
0
  buffer->idx = pos;
682
0
  return_trace (true);
683
0
      }
684
0
    }
685
0
686
0
    return_trace (false);
687
0
  }
688
689
  struct sanitize_closure_t
690
  {
691
    const void *base;
692
    const ValueFormat *valueFormats;
693
    unsigned int len1; /* valueFormats[0].get_len() */
694
    unsigned int stride; /* 1 + len1 + len2 */
695
  };
696
697
  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
698
0
  {
699
0
    TRACE_SANITIZE (this);
700
0
    if (!(c->check_struct (this)
701
0
       && c->check_array (arrayZ, HBUINT16::static_size * closure->stride, len))) return_trace (false);
702
0
703
0
    unsigned int count = len;
704
0
    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
705
0
    return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
706
0
      closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
707
0
  }
708
709
  protected:
710
  HBUINT16  len;      /* Number of PairValueRecords */
711
  HBUINT16  arrayZ[VAR];    /* Array of PairValueRecords--ordered
712
           * by GlyphID of the second glyph */
713
  public:
714
  DEFINE_SIZE_ARRAY (2, arrayZ);
715
};
716
717
struct PairPosFormat1
718
{
719
  inline bool intersects (const hb_set_t *glyphs) const
720
0
  {
721
0
    unsigned int count = pairSet.len;
722
0
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
723
0
    {
724
0
      if (unlikely (iter.get_coverage () >= count))
725
0
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
726
0
      if (glyphs->has (iter.get_glyph ()) &&
727
0
    (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
728
0
        return true;
729
0
    }
730
0
    return false;
731
0
  }
732
733
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
734
0
  {
735
0
    TRACE_COLLECT_GLYPHS (this);
736
0
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
737
0
    unsigned int count = pairSet.len;
738
0
    for (unsigned int i = 0; i < count; i++)
739
0
      (this+pairSet[i]).collect_glyphs (c, valueFormat);
740
0
  }
741
742
  inline const Coverage &get_coverage (void) const
743
0
  { return this+coverage; }
744
745
  inline bool apply (hb_ot_apply_context_t *c) const
746
0
  {
747
0
    TRACE_APPLY (this);
748
0
    hb_buffer_t *buffer = c->buffer;
749
0
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
750
0
    if (likely (index == NOT_COVERED)) return_trace (false);
751
0
752
0
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
753
0
    skippy_iter.reset (buffer->idx, 1);
754
0
    if (!skippy_iter.next ()) return_trace (false);
755
0
756
0
    return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx));
757
0
  }
758
759
  inline bool subset (hb_subset_context_t *c) const
760
0
  {
761
0
    TRACE_SUBSET (this);
762
0
    // TODO(subset)
763
0
    return_trace (false);
764
0
  }
765
766
  inline bool sanitize (hb_sanitize_context_t *c) const
767
0
  {
768
0
    TRACE_SANITIZE (this);
769
0
770
0
    if (!c->check_struct (this)) return_trace (false);
771
0
772
0
    unsigned int len1 = valueFormat[0].get_len ();
773
0
    unsigned int len2 = valueFormat[1].get_len ();
774
0
    PairSet::sanitize_closure_t closure =
775
0
    {
776
0
      this,
777
0
      valueFormat,
778
0
      len1,
779
0
      1 + len1 + len2
780
0
    };
781
0
782
0
    return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
783
0
  }
784
785
  protected:
786
  HBUINT16  format;     /* Format identifier--format = 1 */
787
  OffsetTo<Coverage>
788
    coverage;   /* Offset to Coverage table--from
789
           * beginning of subtable */
790
  ValueFormat valueFormat[2];   /* [0] Defines the types of data in
791
           * ValueRecord1--for the first glyph
792
           * in the pair--may be zero (0) */
793
          /* [1] Defines the types of data in
794
           * ValueRecord2--for the second glyph
795
           * in the pair--may be zero (0) */
796
  OffsetArrayOf<PairSet>
797
    pairSet;    /* Array of PairSet tables
798
           * ordered by Coverage Index */
799
  public:
800
  DEFINE_SIZE_ARRAY (10, pairSet);
801
};
802
803
struct PairPosFormat2
804
{
805
  inline bool intersects (const hb_set_t *glyphs) const
806
0
  {
807
0
    return (this+coverage).intersects (glyphs) &&
808
0
     (this+classDef2).intersects (glyphs);
809
0
  }
810
811
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
812
0
  {
813
0
    TRACE_COLLECT_GLYPHS (this);
814
0
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
815
0
    if (unlikely (!(this+classDef2).add_coverage (c->input))) return;
816
0
  }
817
818
  inline const Coverage &get_coverage (void) const
819
0
  { return this+coverage; }
820
821
  inline bool apply (hb_ot_apply_context_t *c) const
822
0
  {
823
0
    TRACE_APPLY (this);
824
0
    hb_buffer_t *buffer = c->buffer;
825
0
    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
826
0
    if (likely (index == NOT_COVERED)) return_trace (false);
827
0
828
0
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
829
0
    skippy_iter.reset (buffer->idx, 1);
830
0
    if (!skippy_iter.next ()) return_trace (false);
831
0
832
0
    unsigned int len1 = valueFormat1.get_len ();
833
0
    unsigned int len2 = valueFormat2.get_len ();
834
0
    unsigned int record_len = len1 + len2;
835
0
836
0
    unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
837
0
    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
838
0
    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
839
0
840
0
    buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1);
841
0
    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
842
0
    valueFormat1.apply_value (c, this, v, buffer->cur_pos());
843
0
    valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]);
844
0
845
0
    buffer->idx = skippy_iter.idx;
846
0
    if (len2)
847
0
      buffer->idx++;
848
0
849
0
    return_trace (true);
850
0
  }
851
852
  inline bool subset (hb_subset_context_t *c) const
853
0
  {
854
0
    TRACE_SUBSET (this);
855
0
    // TODO(subset)
856
0
    return_trace (false);
857
0
  }
858
859
  inline bool sanitize (hb_sanitize_context_t *c) const
860
0
  {
861
0
    TRACE_SANITIZE (this);
862
0
    if (!(c->check_struct (this)
863
0
       && coverage.sanitize (c, this)
864
0
       && classDef1.sanitize (c, this)
865
0
       && classDef2.sanitize (c, this))) return_trace (false);
866
0
867
0
    unsigned int len1 = valueFormat1.get_len ();
868
0
    unsigned int len2 = valueFormat2.get_len ();
869
0
    unsigned int stride = len1 + len2;
870
0
    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
871
0
    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
872
0
    return_trace (c->check_array (values, record_size, count) &&
873
0
      valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
874
0
      valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
875
0
  }
876
877
  protected:
878
  HBUINT16  format;     /* Format identifier--format = 2 */
879
  OffsetTo<Coverage>
880
    coverage;   /* Offset to Coverage table--from
881
           * beginning of subtable */
882
  ValueFormat valueFormat1;   /* ValueRecord definition--for the
883
           * first glyph of the pair--may be zero
884
           * (0) */
885
  ValueFormat valueFormat2;   /* ValueRecord definition--for the
886
           * second glyph of the pair--may be
887
           * zero (0) */
888
  OffsetTo<ClassDef>
889
    classDef1;    /* Offset to ClassDef table--from
890
           * beginning of PairPos subtable--for
891
           * the first glyph of the pair */
892
  OffsetTo<ClassDef>
893
    classDef2;    /* Offset to ClassDef table--from
894
           * beginning of PairPos subtable--for
895
           * the second glyph of the pair */
896
  HBUINT16  class1Count;    /* Number of classes in ClassDef1
897
           * table--includes Class0 */
898
  HBUINT16  class2Count;    /* Number of classes in ClassDef2
899
           * table--includes Class0 */
900
  ValueRecord values;     /* Matrix of value pairs:
901
           * class1-major, class2-minor,
902
           * Each entry has value1 and value2 */
903
  public:
904
  DEFINE_SIZE_ARRAY (16, values);
905
};
906
907
struct PairPos
908
{
909
  template <typename context_t>
910
  inline typename context_t::return_t dispatch (context_t *c) const
911
0
  {
912
0
    TRACE_DISPATCH (this, u.format);
913
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
914
0
    switch (u.format) {
915
0
    case 1: return_trace (c->dispatch (u.format1));
916
0
    case 2: return_trace (c->dispatch (u.format2));
917
0
    default:return_trace (c->default_return_value ());
918
0
    }
919
0
  }
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::PairPos::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::PairPos::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >::return_t OT::PairPos::dispatch<OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > > >(OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::PairPos::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: hb_get_subtables_context_t::return_t OT::PairPos::dispatch<hb_get_subtables_context_t>(hb_get_subtables_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::PairPos::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::PairPos::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
920
921
  protected:
922
  union {
923
  HBUINT16    format;   /* Format identifier */
924
  PairPosFormat1  format1;
925
  PairPosFormat2  format2;
926
  } u;
927
};
928
929
930
struct EntryExitRecord
931
{
932
  friend struct CursivePosFormat1;
933
934
  inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
935
0
  {
936
0
    TRACE_SANITIZE (this);
937
0
    return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
938
0
  }
939
940
  protected:
941
  OffsetTo<Anchor>
942
    entryAnchor;    /* Offset to EntryAnchor table--from
943
           * beginning of CursivePos
944
           * subtable--may be NULL */
945
  OffsetTo<Anchor>
946
    exitAnchor;   /* Offset to ExitAnchor table--from
947
           * beginning of CursivePos
948
           * subtable--may be NULL */
949
  public:
950
  DEFINE_SIZE_STATIC (4);
951
};
952
953
static void
954
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
955
956
struct CursivePosFormat1
957
{
958
  inline bool intersects (const hb_set_t *glyphs) const
959
0
  { return (this+coverage).intersects (glyphs); }
960
961
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
962
0
  {
963
0
    TRACE_COLLECT_GLYPHS (this);
964
0
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
965
0
  }
966
967
  inline const Coverage &get_coverage (void) const
968
0
  { return this+coverage; }
969
970
  inline bool apply (hb_ot_apply_context_t *c) const
971
0
  {
972
0
    TRACE_APPLY (this);
973
0
    hb_buffer_t *buffer = c->buffer;
974
0
975
0
    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
976
0
    if (!this_record.exitAnchor) return_trace (false);
977
0
978
0
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
979
0
    skippy_iter.reset (buffer->idx, 1);
980
0
    if (!skippy_iter.next ()) return_trace (false);
981
0
982
0
    const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
983
0
    if (!next_record.entryAnchor) return_trace (false);
984
0
985
0
    unsigned int i = buffer->idx;
986
0
    unsigned int j = skippy_iter.idx;
987
0
988
0
    buffer->unsafe_to_break (i, j);
989
0
    float entry_x, entry_y, exit_x, exit_y;
990
0
    (this+this_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y);
991
0
    (this+next_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y);
992
0
993
0
    hb_glyph_position_t *pos = buffer->pos;
994
0
995
0
    hb_position_t d;
996
0
    /* Main-direction adjustment */
997
0
    switch (c->direction) {
998
0
      case HB_DIRECTION_LTR:
999
0
  pos[i].x_advance  = round (exit_x) + pos[i].x_offset;
1000
0
1001
0
  d = round (entry_x) + pos[j].x_offset;
1002
0
  pos[j].x_advance -= d;
1003
0
  pos[j].x_offset  -= d;
1004
0
  break;
1005
0
      case HB_DIRECTION_RTL:
1006
0
  d = round (exit_x) + pos[i].x_offset;
1007
0
  pos[i].x_advance -= d;
1008
0
  pos[i].x_offset  -= d;
1009
0
1010
0
  pos[j].x_advance  = round (entry_x) + pos[j].x_offset;
1011
0
  break;
1012
0
      case HB_DIRECTION_TTB:
1013
0
  pos[i].y_advance  = round (exit_y) + pos[i].y_offset;
1014
0
1015
0
  d = round (entry_y) + pos[j].y_offset;
1016
0
  pos[j].y_advance -= d;
1017
0
  pos[j].y_offset  -= d;
1018
0
  break;
1019
0
      case HB_DIRECTION_BTT:
1020
0
  d = round (exit_y) + pos[i].y_offset;
1021
0
  pos[i].y_advance -= d;
1022
0
  pos[i].y_offset  -= d;
1023
0
1024
0
  pos[j].y_advance  = round (entry_y);
1025
0
  break;
1026
0
      case HB_DIRECTION_INVALID:
1027
0
      default:
1028
0
  break;
1029
0
    }
1030
0
1031
0
    /* Cross-direction adjustment */
1032
0
1033
0
    /* We attach child to parent (think graph theory and rooted trees whereas
1034
0
     * the root stays on baseline and each node aligns itself against its
1035
0
     * parent.
1036
0
     *
1037
0
     * Optimize things for the case of RightToLeft, as that's most common in
1038
0
     * Arabinc. */
1039
0
    unsigned int child  = i;
1040
0
    unsigned int parent = j;
1041
0
    hb_position_t x_offset = entry_x - exit_x;
1042
0
    hb_position_t y_offset = entry_y - exit_y;
1043
0
    if  (!(c->lookup_props & LookupFlag::RightToLeft))
1044
0
    {
1045
0
      unsigned int k = child;
1046
0
      child = parent;
1047
0
      parent = k;
1048
0
      x_offset = -x_offset;
1049
0
      y_offset = -y_offset;
1050
0
    }
1051
0
1052
0
    /* If child was already connected to someone else, walk through its old
1053
0
     * chain and reverse the link direction, such that the whole tree of its
1054
0
     * previous connection now attaches to new parent.  Watch out for case
1055
0
     * where new parent is on the path from old chain...
1056
0
     */
1057
0
    reverse_cursive_minor_offset (pos, child, c->direction, parent);
1058
0
1059
0
    pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
1060
0
    pos[child].attach_chain() = (int) parent - (int) child;
1061
0
    buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
1062
0
    if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
1063
0
      pos[child].y_offset = y_offset;
1064
0
    else
1065
0
      pos[child].x_offset = x_offset;
1066
0
1067
0
    buffer->idx = j;
1068
0
    return_trace (true);
1069
0
  }
1070
1071
  inline bool subset (hb_subset_context_t *c) const
1072
0
  {
1073
0
    TRACE_SUBSET (this);
1074
0
    // TODO(subset)
1075
0
    return_trace (false);
1076
0
  }
1077
1078
  inline bool sanitize (hb_sanitize_context_t *c) const
1079
0
  {
1080
0
    TRACE_SANITIZE (this);
1081
0
    return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
1082
0
  }
1083
1084
  protected:
1085
  HBUINT16  format;     /* Format identifier--format = 1 */
1086
  OffsetTo<Coverage>
1087
    coverage;   /* Offset to Coverage table--from
1088
           * beginning of subtable */
1089
  ArrayOf<EntryExitRecord>
1090
    entryExitRecord;  /* Array of EntryExit records--in
1091
           * Coverage Index order */
1092
  public:
1093
  DEFINE_SIZE_ARRAY (6, entryExitRecord);
1094
};
1095
1096
struct CursivePos
1097
{
1098
  template <typename context_t>
1099
  inline typename context_t::return_t dispatch (context_t *c) const
1100
0
  {
1101
0
    TRACE_DISPATCH (this, u.format);
1102
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1103
0
    switch (u.format) {
1104
0
    case 1: return_trace (c->dispatch (u.format1));
1105
0
    default:return_trace (c->default_return_value ());
1106
0
    }
1107
0
  }
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::CursivePos::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::CursivePos::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >::return_t OT::CursivePos::dispatch<OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > > >(OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::CursivePos::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: hb_get_subtables_context_t::return_t OT::CursivePos::dispatch<hb_get_subtables_context_t>(hb_get_subtables_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::CursivePos::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::CursivePos::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
1108
1109
  protected:
1110
  union {
1111
  HBUINT16    format;   /* Format identifier */
1112
  CursivePosFormat1 format1;
1113
  } u;
1114
};
1115
1116
1117
typedef AnchorMatrix BaseArray;   /* base-major--
1118
           * in order of BaseCoverage Index--,
1119
           * mark-minor--
1120
           * ordered by class--zero-based. */
1121
1122
struct MarkBasePosFormat1
1123
{
1124
  inline bool intersects (const hb_set_t *glyphs) const
1125
0
  { return (this+markCoverage).intersects (glyphs) &&
1126
0
     (this+baseCoverage).intersects (glyphs); }
1127
1128
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1129
0
  {
1130
0
    TRACE_COLLECT_GLYPHS (this);
1131
0
    if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
1132
0
    if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return;
1133
0
  }
1134
1135
  inline const Coverage &get_coverage (void) const
1136
0
  { return this+markCoverage; }
1137
1138
  inline bool apply (hb_ot_apply_context_t *c) const
1139
0
  {
1140
0
    TRACE_APPLY (this);
1141
0
    hb_buffer_t *buffer = c->buffer;
1142
0
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1143
0
    if (likely (mark_index == NOT_COVERED)) return_trace (false);
1144
0
1145
0
    /* Now we search backwards for a non-mark glyph */
1146
0
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1147
0
    skippy_iter.reset (buffer->idx, 1);
1148
0
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1149
0
    do {
1150
0
      if (!skippy_iter.prev ()) return_trace (false);
1151
0
      /* We only want to attach to the first of a MultipleSubst sequence.
1152
0
       * https://github.com/harfbuzz/harfbuzz/issues/740
1153
0
       * Reject others...
1154
0
       * ...but stop if we find a mark in the MultipleSubst sequence:
1155
0
       * https://github.com/harfbuzz/harfbuzz/issues/1020 */
1156
0
      if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
1157
0
    0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
1158
0
    (skippy_iter.idx == 0 ||
1159
0
     _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
1160
0
     _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
1161
0
     _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
1162
0
     _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
1163
0
     _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
1164
0
     ))
1165
0
  break;
1166
0
      skippy_iter.reject ();
1167
0
    } while (1);
1168
0
1169
0
    /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
1170
0
    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1171
0
1172
0
    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
1173
0
    if (base_index == NOT_COVERED) return_trace (false);
1174
0
1175
0
    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
1176
0
  }
1177
1178
  inline bool subset (hb_subset_context_t *c) const
1179
0
  {
1180
0
    TRACE_SUBSET (this);
1181
0
    // TODO(subset)
1182
0
    return_trace (false);
1183
0
  }
1184
1185
  inline bool sanitize (hb_sanitize_context_t *c) const
1186
0
  {
1187
0
    TRACE_SANITIZE (this);
1188
0
    return_trace (c->check_struct (this) &&
1189
0
      markCoverage.sanitize (c, this) &&
1190
0
      baseCoverage.sanitize (c, this) &&
1191
0
      markArray.sanitize (c, this) &&
1192
0
      baseArray.sanitize (c, this, (unsigned int) classCount));
1193
0
  }
1194
1195
  protected:
1196
  HBUINT16  format;     /* Format identifier--format = 1 */
1197
  OffsetTo<Coverage>
1198
    markCoverage;   /* Offset to MarkCoverage table--from
1199
           * beginning of MarkBasePos subtable */
1200
  OffsetTo<Coverage>
1201
    baseCoverage;   /* Offset to BaseCoverage table--from
1202
           * beginning of MarkBasePos subtable */
1203
  HBUINT16  classCount;   /* Number of classes defined for marks */
1204
  OffsetTo<MarkArray>
1205
    markArray;    /* Offset to MarkArray table--from
1206
           * beginning of MarkBasePos subtable */
1207
  OffsetTo<BaseArray>
1208
    baseArray;    /* Offset to BaseArray table--from
1209
           * beginning of MarkBasePos subtable */
1210
  public:
1211
  DEFINE_SIZE_STATIC (12);
1212
};
1213
1214
struct MarkBasePos
1215
{
1216
  template <typename context_t>
1217
  inline typename context_t::return_t dispatch (context_t *c) const
1218
0
  {
1219
0
    TRACE_DISPATCH (this, u.format);
1220
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1221
0
    switch (u.format) {
1222
0
    case 1: return_trace (c->dispatch (u.format1));
1223
0
    default:return_trace (c->default_return_value ());
1224
0
    }
1225
0
  }
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::MarkBasePos::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::MarkBasePos::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >::return_t OT::MarkBasePos::dispatch<OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > > >(OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::MarkBasePos::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: hb_get_subtables_context_t::return_t OT::MarkBasePos::dispatch<hb_get_subtables_context_t>(hb_get_subtables_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::MarkBasePos::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::MarkBasePos::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
1226
1227
  protected:
1228
  union {
1229
  HBUINT16    format;   /* Format identifier */
1230
  MarkBasePosFormat1  format1;
1231
  } u;
1232
};
1233
1234
1235
typedef AnchorMatrix LigatureAttach;  /* component-major--
1236
           * in order of writing direction--,
1237
           * mark-minor--
1238
           * ordered by class--zero-based. */
1239
1240
typedef OffsetListOf<LigatureAttach> LigatureArray;
1241
          /* Array of LigatureAttach
1242
           * tables ordered by
1243
           * LigatureCoverage Index */
1244
1245
struct MarkLigPosFormat1
1246
{
1247
  inline bool intersects (const hb_set_t *glyphs) const
1248
0
  { return (this+markCoverage).intersects (glyphs) &&
1249
0
     (this+ligatureCoverage).intersects (glyphs); }
1250
1251
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1252
0
  {
1253
0
    TRACE_COLLECT_GLYPHS (this);
1254
0
    if (unlikely (!(this+markCoverage).add_coverage (c->input))) return;
1255
0
    if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return;
1256
0
  }
1257
1258
  inline const Coverage &get_coverage (void) const
1259
0
  { return this+markCoverage; }
1260
1261
  inline bool apply (hb_ot_apply_context_t *c) const
1262
0
  {
1263
0
    TRACE_APPLY (this);
1264
0
    hb_buffer_t *buffer = c->buffer;
1265
0
    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
1266
0
    if (likely (mark_index == NOT_COVERED)) return_trace (false);
1267
0
1268
0
    /* Now we search backwards for a non-mark glyph */
1269
0
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1270
0
    skippy_iter.reset (buffer->idx, 1);
1271
0
    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1272
0
    if (!skippy_iter.prev ()) return_trace (false);
1273
0
1274
0
    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
1275
0
    //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1276
0
1277
0
    unsigned int j = skippy_iter.idx;
1278
0
    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
1279
0
    if (lig_index == NOT_COVERED) return_trace (false);
1280
0
1281
0
    const LigatureArray& lig_array = this+ligatureArray;
1282
0
    const LigatureAttach& lig_attach = lig_array[lig_index];
1283
0
1284
0
    /* Find component to attach to */
1285
0
    unsigned int comp_count = lig_attach.rows;
1286
0
    if (unlikely (!comp_count)) return_trace (false);
1287
0
1288
0
    /* We must now check whether the ligature ID of the current mark glyph
1289
0
     * is identical to the ligature ID of the found ligature.  If yes, we
1290
0
     * can directly use the component index.  If not, we attach the mark
1291
0
     * glyph to the last component of the ligature. */
1292
0
    unsigned int comp_index;
1293
0
    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1294
0
    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1295
0
    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1296
0
    if (lig_id && lig_id == mark_id && mark_comp > 0)
1297
0
      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
1298
0
    else
1299
0
      comp_index = comp_count - 1;
1300
0
1301
0
    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
1302
0
  }
1303
1304
  inline bool subset (hb_subset_context_t *c) const
1305
0
  {
1306
0
    TRACE_SUBSET (this);
1307
0
    // TODO(subset)
1308
0
    return_trace (false);
1309
0
  }
1310
1311
  inline bool sanitize (hb_sanitize_context_t *c) const
1312
0
  {
1313
0
    TRACE_SANITIZE (this);
1314
0
    return_trace (c->check_struct (this) &&
1315
0
      markCoverage.sanitize (c, this) &&
1316
0
      ligatureCoverage.sanitize (c, this) &&
1317
0
      markArray.sanitize (c, this) &&
1318
0
      ligatureArray.sanitize (c, this, (unsigned int) classCount));
1319
0
  }
1320
1321
  protected:
1322
  HBUINT16  format;     /* Format identifier--format = 1 */
1323
  OffsetTo<Coverage>
1324
    markCoverage;   /* Offset to Mark Coverage table--from
1325
           * beginning of MarkLigPos subtable */
1326
  OffsetTo<Coverage>
1327
    ligatureCoverage; /* Offset to Ligature Coverage
1328
           * table--from beginning of MarkLigPos
1329
           * subtable */
1330
  HBUINT16  classCount;   /* Number of defined mark classes */
1331
  OffsetTo<MarkArray>
1332
    markArray;    /* Offset to MarkArray table--from
1333
           * beginning of MarkLigPos subtable */
1334
  OffsetTo<LigatureArray>
1335
    ligatureArray;    /* Offset to LigatureArray table--from
1336
           * beginning of MarkLigPos subtable */
1337
  public:
1338
  DEFINE_SIZE_STATIC (12);
1339
};
1340
1341
struct MarkLigPos
1342
{
1343
  template <typename context_t>
1344
  inline typename context_t::return_t dispatch (context_t *c) const
1345
0
  {
1346
0
    TRACE_DISPATCH (this, u.format);
1347
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1348
0
    switch (u.format) {
1349
0
    case 1: return_trace (c->dispatch (u.format1));
1350
0
    default:return_trace (c->default_return_value ());
1351
0
    }
1352
0
  }
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::MarkLigPos::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::MarkLigPos::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >::return_t OT::MarkLigPos::dispatch<OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > > >(OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::MarkLigPos::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: hb_get_subtables_context_t::return_t OT::MarkLigPos::dispatch<hb_get_subtables_context_t>(hb_get_subtables_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::MarkLigPos::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::MarkLigPos::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
1353
1354
  protected:
1355
  union {
1356
  HBUINT16    format;   /* Format identifier */
1357
  MarkLigPosFormat1 format1;
1358
  } u;
1359
};
1360
1361
1362
typedef AnchorMatrix Mark2Array;  /* mark2-major--
1363
           * in order of Mark2Coverage Index--,
1364
           * mark1-minor--
1365
           * ordered by class--zero-based. */
1366
1367
struct MarkMarkPosFormat1
1368
{
1369
  inline bool intersects (const hb_set_t *glyphs) const
1370
0
  { return (this+mark1Coverage).intersects (glyphs) &&
1371
0
     (this+mark2Coverage).intersects (glyphs); }
1372
1373
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1374
0
  {
1375
0
    TRACE_COLLECT_GLYPHS (this);
1376
0
    if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return;
1377
0
    if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return;
1378
0
  }
1379
1380
  inline const Coverage &get_coverage (void) const
1381
0
  { return this+mark1Coverage; }
1382
1383
  inline bool apply (hb_ot_apply_context_t *c) const
1384
0
  {
1385
0
    TRACE_APPLY (this);
1386
0
    hb_buffer_t *buffer = c->buffer;
1387
0
    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
1388
0
    if (likely (mark1_index == NOT_COVERED)) return_trace (false);
1389
0
1390
0
    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1391
0
    hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1392
0
    skippy_iter.reset (buffer->idx, 1);
1393
0
    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
1394
0
    if (!skippy_iter.prev ()) return_trace (false);
1395
0
1396
0
    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1397
0
1398
0
    unsigned int j = skippy_iter.idx;
1399
0
1400
0
    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
1401
0
    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1402
0
    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
1403
0
    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
1404
0
1405
0
    if (likely (id1 == id2)) {
1406
0
      if (id1 == 0) /* Marks belonging to the same base. */
1407
0
  goto good;
1408
0
      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1409
0
        goto good;
1410
0
    } else {
1411
0
      /* If ligature ids don't match, it may be the case that one of the marks
1412
0
       * itself is a ligature.  In which case match. */
1413
0
      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1414
0
  goto good;
1415
0
    }
1416
0
1417
0
    /* Didn't match. */
1418
0
    return_trace (false);
1419
0
1420
0
    good:
1421
0
    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
1422
0
    if (mark2_index == NOT_COVERED) return_trace (false);
1423
0
1424
0
    return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
1425
0
  }
1426
1427
  inline bool subset (hb_subset_context_t *c) const
1428
0
  {
1429
0
    TRACE_SUBSET (this);
1430
0
    // TODO(subset)
1431
0
    return_trace (false);
1432
0
  }
1433
1434
  inline bool sanitize (hb_sanitize_context_t *c) const
1435
0
  {
1436
0
    TRACE_SANITIZE (this);
1437
0
    return_trace (c->check_struct (this) &&
1438
0
      mark1Coverage.sanitize (c, this) &&
1439
0
      mark2Coverage.sanitize (c, this) &&
1440
0
      mark1Array.sanitize (c, this) &&
1441
0
      mark2Array.sanitize (c, this, (unsigned int) classCount));
1442
0
  }
1443
1444
  protected:
1445
  HBUINT16  format;     /* Format identifier--format = 1 */
1446
  OffsetTo<Coverage>
1447
    mark1Coverage;    /* Offset to Combining Mark1 Coverage
1448
           * table--from beginning of MarkMarkPos
1449
           * subtable */
1450
  OffsetTo<Coverage>
1451
    mark2Coverage;    /* Offset to Combining Mark2 Coverage
1452
           * table--from beginning of MarkMarkPos
1453
           * subtable */
1454
  HBUINT16  classCount;   /* Number of defined mark classes */
1455
  OffsetTo<MarkArray>
1456
    mark1Array;   /* Offset to Mark1Array table--from
1457
           * beginning of MarkMarkPos subtable */
1458
  OffsetTo<Mark2Array>
1459
    mark2Array;   /* Offset to Mark2Array table--from
1460
           * beginning of MarkMarkPos subtable */
1461
  public:
1462
  DEFINE_SIZE_STATIC (12);
1463
};
1464
1465
struct MarkMarkPos
1466
{
1467
  template <typename context_t>
1468
  inline typename context_t::return_t dispatch (context_t *c) const
1469
0
  {
1470
0
    TRACE_DISPATCH (this, u.format);
1471
0
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1472
0
    switch (u.format) {
1473
0
    case 1: return_trace (c->dispatch (u.format1));
1474
0
    default:return_trace (c->default_return_value ());
1475
0
    }
1476
0
  }
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::MarkMarkPos::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::MarkMarkPos::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*) const
Unexecuted instantiation: OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >::return_t OT::MarkMarkPos::dispatch<OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > > >(OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::MarkMarkPos::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: hb_get_subtables_context_t::return_t OT::MarkMarkPos::dispatch<hb_get_subtables_context_t>(hb_get_subtables_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::MarkMarkPos::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::MarkMarkPos::dispatch<hb_subset_context_t>(hb_subset_context_t*) const
1477
1478
  protected:
1479
  union {
1480
  HBUINT16    format;   /* Format identifier */
1481
  MarkMarkPosFormat1  format1;
1482
  } u;
1483
};
1484
1485
1486
struct ContextPos : Context {};
1487
1488
struct ChainContextPos : ChainContext {};
1489
1490
struct ExtensionPos : Extension<ExtensionPos>
1491
{
1492
  typedef struct PosLookupSubTable SubTable;
1493
};
1494
1495
1496
1497
/*
1498
 * PosLookup
1499
 */
1500
1501
1502
struct PosLookupSubTable
1503
{
1504
  friend struct Lookup;
1505
  friend struct PosLookup;
1506
1507
  enum Type {
1508
    Single    = 1,
1509
    Pair    = 2,
1510
    Cursive   = 3,
1511
    MarkBase    = 4,
1512
    MarkLig   = 5,
1513
    MarkMark    = 6,
1514
    Context   = 7,
1515
    ChainContext  = 8,
1516
    Extension   = 9
1517
  };
1518
1519
  template <typename context_t>
1520
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1521
0
  {
1522
0
    TRACE_DISPATCH (this, lookup_type);
1523
0
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1524
0
    switch (lookup_type) {
1525
0
    case Single:    return_trace (u.single.dispatch (c));
1526
0
    case Pair:      return_trace (u.pair.dispatch (c));
1527
0
    case Cursive:   return_trace (u.cursive.dispatch (c));
1528
0
    case MarkBase:    return_trace (u.markBase.dispatch (c));
1529
0
    case MarkLig:   return_trace (u.markLig.dispatch (c));
1530
0
    case MarkMark:    return_trace (u.markMark.dispatch (c));
1531
0
    case Context:   return_trace (u.context.dispatch (c));
1532
0
    case ChainContext:    return_trace (u.chainContext.dispatch (c));
1533
0
    case Extension:   return_trace (u.extension.dispatch (c));
1534
0
    default:      return_trace (c->default_return_value ());
1535
0
    }
1536
0
  }
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::PosLookupSubTable::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*, unsigned int) const
Unexecuted instantiation: hb_sanitize_context_t::return_t OT::PosLookupSubTable::dispatch<hb_sanitize_context_t>(hb_sanitize_context_t*, unsigned int) const
Unexecuted instantiation: OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >::return_t OT::PosLookupSubTable::dispatch<OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > > >(OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >*, unsigned int) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::PosLookupSubTable::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*, unsigned int) const
Unexecuted instantiation: hb_get_subtables_context_t::return_t OT::PosLookupSubTable::dispatch<hb_get_subtables_context_t>(hb_get_subtables_context_t*, unsigned int) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::PosLookupSubTable::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*, unsigned int) const
Unexecuted instantiation: hb_subset_context_t::return_t OT::PosLookupSubTable::dispatch<hb_subset_context_t>(hb_subset_context_t*, unsigned int) const
1537
1538
  protected:
1539
  union {
1540
  HBUINT16    sub_format;
1541
  SinglePos   single;
1542
  PairPos   pair;
1543
  CursivePos    cursive;
1544
  MarkBasePos   markBase;
1545
  MarkLigPos    markLig;
1546
  MarkMarkPos   markMark;
1547
  ContextPos    context;
1548
  ChainContextPos chainContext;
1549
  ExtensionPos    extension;
1550
  } u;
1551
  public:
1552
  DEFINE_SIZE_UNION (2, sub_format);
1553
};
1554
1555
1556
struct PosLookup : Lookup
1557
{
1558
  typedef struct PosLookupSubTable SubTable;
1559
1560
  inline const SubTable& get_subtable (unsigned int i) const
1561
0
  { return Lookup::get_subtable<SubTable> (i); }
1562
1563
  inline bool is_reverse (void) const
1564
0
  {
1565
0
    return false;
1566
0
  }
1567
1568
  inline bool apply (hb_ot_apply_context_t *c) const
1569
0
  {
1570
0
    TRACE_APPLY (this);
1571
0
    return_trace (dispatch (c));
1572
0
  }
1573
1574
  inline bool intersects (const hb_set_t *glyphs) const
1575
0
  {
1576
0
    hb_intersects_context_t c (glyphs);
1577
0
    return dispatch (&c);
1578
0
  }
1579
1580
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1581
0
  {
1582
0
    TRACE_COLLECT_GLYPHS (this);
1583
0
    return_trace (dispatch (c));
1584
0
  }
1585
1586
  template <typename set_t>
1587
  inline void add_coverage (set_t *glyphs) const
1588
0
  {
1589
0
    hb_add_coverage_context_t<set_t> c (glyphs);
1590
0
    dispatch (&c);
1591
0
  }
1592
1593
  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
1594
1595
  template <typename context_t>
1596
  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1597
1598
  template <typename context_t>
1599
  inline typename context_t::return_t dispatch (context_t *c) const
1600
0
  { return Lookup::dispatch<SubTable> (c); }
Unexecuted instantiation: OT::hb_collect_glyphs_context_t::return_t OT::PosLookup::dispatch<OT::hb_collect_glyphs_context_t>(OT::hb_collect_glyphs_context_t*) const
Unexecuted instantiation: OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >::return_t OT::PosLookup::dispatch<OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > > >(OT::hb_add_coverage_context_t<hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 4u>, hb_set_digest_combiner_t<hb_set_digest_lowest_bits_t<unsigned long, 0u>, hb_set_digest_lowest_bits_t<unsigned long, 9u> > > >*) const
Unexecuted instantiation: OT::hb_ot_apply_context_t::return_t OT::PosLookup::dispatch<OT::hb_ot_apply_context_t>(OT::hb_ot_apply_context_t*) const
Unexecuted instantiation: hb_get_subtables_context_t::return_t OT::PosLookup::dispatch<hb_get_subtables_context_t>(hb_get_subtables_context_t*) const
Unexecuted instantiation: OT::hb_intersects_context_t::return_t OT::PosLookup::dispatch<OT::hb_intersects_context_t>(OT::hb_intersects_context_t*) const
1601
1602
  inline bool subset (hb_subset_context_t *c) const
1603
0
  { return Lookup::subset<SubTable> (c); }
1604
1605
  inline bool sanitize (hb_sanitize_context_t *c) const
1606
0
  { return Lookup::sanitize<SubTable> (c); }
1607
};
1608
1609
/*
1610
 * GPOS -- Glyph Positioning
1611
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
1612
 */
1613
1614
struct GPOS : GSUBGPOS
1615
{
1616
  static const hb_tag_t tableTag  = HB_OT_TAG_GPOS;
1617
1618
  inline const PosLookup& get_lookup (unsigned int i) const
1619
0
  { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1620
1621
  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1622
  static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
1623
  static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
1624
1625
  inline bool subset (hb_subset_context_t *c) const
1626
0
  { return GSUBGPOS::subset<PosLookup> (c); }
1627
1628
  inline bool sanitize (hb_sanitize_context_t *c) const
1629
0
  { return GSUBGPOS::sanitize<PosLookup> (c); }
1630
1631
  typedef GSUBGPOS::accelerator_t<GPOS> accelerator_t;
1632
};
1633
1634
1635
static void
1636
reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
1637
0
{
1638
0
  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
1639
0
  if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
1640
0
    return;
1641
0
1642
0
  pos[i].attach_chain() = 0;
1643
0
1644
0
  unsigned int j = (int) i + chain;
1645
0
1646
0
  /* Stop if we see new parent in the chain. */
1647
0
  if (j == new_parent)
1648
0
    return;
1649
0
1650
0
  reverse_cursive_minor_offset (pos, j, direction, new_parent);
1651
0
1652
0
  if (HB_DIRECTION_IS_HORIZONTAL (direction))
1653
0
    pos[j].y_offset = -pos[i].y_offset;
1654
0
  else
1655
0
    pos[j].x_offset = -pos[i].x_offset;
1656
0
1657
0
  pos[j].attach_chain() = -chain;
1658
0
  pos[j].attach_type() = type;
1659
0
}
1660
static void
1661
propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1662
0
{
1663
0
  /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
1664
0
   * offset of glyph they are attached to. */
1665
0
  int chain = pos[i].attach_chain(), type = pos[i].attach_type();
1666
0
  if (likely (!chain))
1667
0
    return;
1668
0
1669
0
  unsigned int j = (int) i + chain;
1670
0
1671
0
  pos[i].attach_chain() = 0;
1672
0
1673
0
  propagate_attachment_offsets (pos, j, direction);
1674
0
1675
0
  assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
1676
0
1677
0
  if (type & ATTACH_TYPE_CURSIVE)
1678
0
  {
1679
0
    if (HB_DIRECTION_IS_HORIZONTAL (direction))
1680
0
      pos[i].y_offset += pos[j].y_offset;
1681
0
    else
1682
0
      pos[i].x_offset += pos[j].x_offset;
1683
0
  }
1684
0
  else /*if (type & ATTACH_TYPE_MARK)*/
1685
0
  {
1686
0
    pos[i].x_offset += pos[j].x_offset;
1687
0
    pos[i].y_offset += pos[j].y_offset;
1688
0
1689
0
    assert (j < i);
1690
0
    if (HB_DIRECTION_IS_FORWARD (direction))
1691
0
      for (unsigned int k = j; k < i; k++) {
1692
0
  pos[i].x_offset -= pos[k].x_advance;
1693
0
  pos[i].y_offset -= pos[k].y_advance;
1694
0
      }
1695
0
    else
1696
0
      for (unsigned int k = j + 1; k < i + 1; k++) {
1697
0
  pos[i].x_offset += pos[k].x_advance;
1698
0
  pos[i].y_offset += pos[k].y_advance;
1699
0
      }
1700
0
  }
1701
0
}
1702
1703
void
1704
GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1705
0
{
1706
0
  unsigned int count = buffer->len;
1707
0
  for (unsigned int i = 0; i < count; i++)
1708
0
    buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
1709
0
}
1710
1711
void
1712
GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1713
0
{
1714
0
  //_hb_buffer_assert_gsubgpos_vars (buffer);
1715
0
}
1716
1717
void
1718
GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1719
0
{
1720
0
  _hb_buffer_assert_gsubgpos_vars (buffer);
1721
0
1722
0
  unsigned int len;
1723
0
  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1724
0
  hb_direction_t direction = buffer->props.direction;
1725
0
1726
0
  /* Handle attachments */
1727
0
  if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
1728
0
    for (unsigned int i = 0; i < len; i++)
1729
0
      propagate_attachment_offsets (pos, i, direction);
1730
0
}
1731
1732
1733
/* Out-of-class implementation for methods recursing */
1734
1735
template <typename context_t>
1736
/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1737
{
1738
  const PosLookup &l = _get_gpos_relaxed (c->face)->get_lookup (lookup_index);
1739
  return l.dispatch (c);
1740
}
1741
1742
/*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
1743
0
{
1744
0
  const PosLookup &l = _get_gpos_relaxed (c->face).get_lookup (lookup_index);
1745
0
  unsigned int saved_lookup_props = c->lookup_props;
1746
0
  unsigned int saved_lookup_index = c->lookup_index;
1747
0
  c->set_lookup_index (lookup_index);
1748
0
  c->set_lookup_props (l.get_props ());
1749
0
  bool ret = l.dispatch (c);
1750
0
  c->set_lookup_index (saved_lookup_index);
1751
0
  c->set_lookup_props (saved_lookup_props);
1752
0
  return ret;
1753
0
}
1754
1755
struct GPOS_accelerator_t : GPOS::accelerator_t {};
1756
1757
1758
#undef attach_chain
1759
#undef attach_type
1760
1761
1762
} /* namespace OT */
1763
1764
1765
#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */