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-private.hh"
33
34
35 namespace OT {
36
37
38 /* buffer **position** var allocations */
39 #define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */
40 #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 USHORT Value;
55
56 typedef Value ValueRecord[VAR];
57
58 struct ValueFormat : USHORT
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 SHORT xPlacement; /* Horizontal adjustment for
78 * placement--in design units */
79 SHORT yPlacement; /* Vertical adjustment for
80 * placement--in design units */
81 SHORT xAdvance; /* Horizontal adjustment for
82 * advance--in design units (only used
83 * for horizontal writing) */
84 SHORT 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
get_lenOT::ValueFormat101 inline unsigned int get_len (void) const
102 { return _hb_popcount32 ((unsigned int) *this); }
get_sizeOT::ValueFormat103 inline unsigned int get_size (void) const
104 { return get_len () * Value::static_size; }
105
apply_valueOT::ValueFormat106 void apply_value (hb_font_t *font,
107 hb_direction_t direction,
108 const void *base,
109 const Value *values,
110 hb_glyph_position_t &glyph_pos) const
111 {
112 unsigned int x_ppem, y_ppem;
113 unsigned int format = *this;
114 hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
115
116 if (!format) return;
117
118 if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
119 if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
120 if (format & xAdvance) {
121 if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
122 values++;
123 }
124 /* y_advance values grow downward but font-space grows upward, hence negation */
125 if (format & yAdvance) {
126 if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
127 values++;
128 }
129
130 if (!has_device ()) return;
131
132 x_ppem = font->x_ppem;
133 y_ppem = font->y_ppem;
134
135 if (!x_ppem && !y_ppem) return;
136
137 /* pixel -> fractional pixel */
138 if (format & xPlaDevice) {
139 if (x_ppem) glyph_pos.x_offset += (base + get_device (values)).get_x_delta (font);
140 values++;
141 }
142 if (format & yPlaDevice) {
143 if (y_ppem) glyph_pos.y_offset += (base + get_device (values)).get_y_delta (font);
144 values++;
145 }
146 if (format & xAdvDevice) {
147 if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
148 values++;
149 }
150 if (format & yAdvDevice) {
151 /* y_advance values grow downward but font-space grows upward, hence negation */
152 if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
153 values++;
154 }
155 }
156
157 private:
sanitize_value_devicesOT::ValueFormat158 inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
159 {
160 unsigned int format = *this;
161
162 if (format & xPlacement) values++;
163 if (format & yPlacement) values++;
164 if (format & xAdvance) values++;
165 if (format & yAdvance) values++;
166
167 if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
168 if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
169 if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
170 if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
171
172 return true;
173 }
174
get_deviceOT::ValueFormat175 static inline OffsetTo<Device>& get_device (Value* value)
176 { return *CastP<OffsetTo<Device> > (value); }
get_deviceOT::ValueFormat177 static inline const OffsetTo<Device>& get_device (const Value* value)
178 { return *CastP<OffsetTo<Device> > (value); }
179
get_shortOT::ValueFormat180 static inline const SHORT& get_short (const Value* value)
181 { return *CastP<SHORT> (value); }
182
183 public:
184
has_deviceOT::ValueFormat185 inline bool has_device (void) const {
186 unsigned int format = *this;
187 return (format & devices) != 0;
188 }
189
sanitize_valueOT::ValueFormat190 inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
191 {
192 TRACE_SANITIZE (this);
193 return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
194 }
195
sanitize_valuesOT::ValueFormat196 inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
197 {
198 TRACE_SANITIZE (this);
199 unsigned int len = get_len ();
200
201 if (!c->check_array (values, get_size (), count)) return_trace (false);
202
203 if (!has_device ()) return_trace (true);
204
205 for (unsigned int i = 0; i < count; i++) {
206 if (!sanitize_value_devices (c, base, values))
207 return_trace (false);
208 values += len;
209 }
210
211 return_trace (true);
212 }
213
214 /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
sanitize_values_stride_unsafeOT::ValueFormat215 inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
216 {
217 TRACE_SANITIZE (this);
218
219 if (!has_device ()) return_trace (true);
220
221 for (unsigned int i = 0; i < count; i++) {
222 if (!sanitize_value_devices (c, base, values))
223 return_trace (false);
224 values += stride;
225 }
226
227 return_trace (true);
228 }
229 };
230
231
232 struct AnchorFormat1
233 {
get_anchorOT::AnchorFormat1234 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
235 hb_position_t *x, hb_position_t *y) const
236 {
237 *x = font->em_scale_x (xCoordinate);
238 *y = font->em_scale_y (yCoordinate);
239 }
240
sanitizeOT::AnchorFormat1241 inline bool sanitize (hb_sanitize_context_t *c) const
242 {
243 TRACE_SANITIZE (this);
244 return_trace (c->check_struct (this));
245 }
246
247 protected:
248 USHORT format; /* Format identifier--format = 1 */
249 SHORT xCoordinate; /* Horizontal value--in design units */
250 SHORT yCoordinate; /* Vertical value--in design units */
251 public:
252 DEFINE_SIZE_STATIC (6);
253 };
254
255 struct AnchorFormat2
256 {
get_anchorOT::AnchorFormat2257 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
258 hb_position_t *x, hb_position_t *y) const
259 {
260 unsigned int x_ppem = font->x_ppem;
261 unsigned int y_ppem = font->y_ppem;
262 hb_position_t cx, cy;
263 hb_bool_t ret;
264
265 ret = (x_ppem || y_ppem) &&
266 font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
267 *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
268 *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
269 }
270
sanitizeOT::AnchorFormat2271 inline bool sanitize (hb_sanitize_context_t *c) const
272 {
273 TRACE_SANITIZE (this);
274 return_trace (c->check_struct (this));
275 }
276
277 protected:
278 USHORT format; /* Format identifier--format = 2 */
279 SHORT xCoordinate; /* Horizontal value--in design units */
280 SHORT yCoordinate; /* Vertical value--in design units */
281 USHORT anchorPoint; /* Index to glyph contour point */
282 public:
283 DEFINE_SIZE_STATIC (8);
284 };
285
286 struct AnchorFormat3
287 {
get_anchorOT::AnchorFormat3288 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
289 hb_position_t *x, hb_position_t *y) const
290 {
291 *x = font->em_scale_x (xCoordinate);
292 *y = font->em_scale_y (yCoordinate);
293
294 if (font->x_ppem)
295 *x += (this+xDeviceTable).get_x_delta (font);
296 if (font->y_ppem)
297 *y += (this+yDeviceTable).get_x_delta (font);
298 }
299
sanitizeOT::AnchorFormat3300 inline bool sanitize (hb_sanitize_context_t *c) const
301 {
302 TRACE_SANITIZE (this);
303 return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
304 }
305
306 protected:
307 USHORT format; /* Format identifier--format = 3 */
308 SHORT xCoordinate; /* Horizontal value--in design units */
309 SHORT yCoordinate; /* Vertical value--in design units */
310 OffsetTo<Device>
311 xDeviceTable; /* Offset to Device table for X
312 * coordinate-- from beginning of
313 * Anchor table (may be NULL) */
314 OffsetTo<Device>
315 yDeviceTable; /* Offset to Device table for Y
316 * coordinate-- from beginning of
317 * Anchor table (may be NULL) */
318 public:
319 DEFINE_SIZE_STATIC (10);
320 };
321
322 struct Anchor
323 {
get_anchorOT::Anchor324 inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
325 hb_position_t *x, hb_position_t *y) const
326 {
327 *x = *y = 0;
328 switch (u.format) {
329 case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
330 case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
331 case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
332 default: return;
333 }
334 }
335
sanitizeOT::Anchor336 inline bool sanitize (hb_sanitize_context_t *c) const
337 {
338 TRACE_SANITIZE (this);
339 if (!u.format.sanitize (c)) return_trace (false);
340 switch (u.format) {
341 case 1: return_trace (u.format1.sanitize (c));
342 case 2: return_trace (u.format2.sanitize (c));
343 case 3: return_trace (u.format3.sanitize (c));
344 default:return_trace (true);
345 }
346 }
347
348 protected:
349 union {
350 USHORT format; /* Format identifier */
351 AnchorFormat1 format1;
352 AnchorFormat2 format2;
353 AnchorFormat3 format3;
354 } u;
355 public:
356 DEFINE_SIZE_UNION (2, format);
357 };
358
359
360 struct AnchorMatrix
361 {
get_anchorOT::AnchorMatrix362 inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
363 *found = false;
364 if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
365 *found = !matrixZ[row * cols + col].is_null ();
366 return this+matrixZ[row * cols + col];
367 }
368
sanitizeOT::AnchorMatrix369 inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
370 {
371 TRACE_SANITIZE (this);
372 if (!c->check_struct (this)) return_trace (false);
373 if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
374 unsigned int count = rows * cols;
375 if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
376 for (unsigned int i = 0; i < count; i++)
377 if (!matrixZ[i].sanitize (c, this)) return_trace (false);
378 return_trace (true);
379 }
380
381 USHORT rows; /* Number of rows */
382 protected:
383 OffsetTo<Anchor>
384 matrixZ[VAR]; /* Matrix of offsets to Anchor tables--
385 * from beginning of AnchorMatrix table */
386 public:
387 DEFINE_SIZE_ARRAY (2, matrixZ);
388 };
389
390
391 struct MarkRecord
392 {
393 friend struct MarkArray;
394
sanitizeOT::MarkRecord395 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
396 {
397 TRACE_SANITIZE (this);
398 return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
399 }
400
401 protected:
402 USHORT klass; /* Class defined for this mark */
403 OffsetTo<Anchor>
404 markAnchor; /* Offset to Anchor table--from
405 * beginning of MarkArray table */
406 public:
407 DEFINE_SIZE_STATIC (4);
408 };
409
410 struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
411 {
applyOT::MarkArray412 inline bool apply (hb_apply_context_t *c,
413 unsigned int mark_index, unsigned int glyph_index,
414 const AnchorMatrix &anchors, unsigned int class_count,
415 unsigned int glyph_pos) const
416 {
417 TRACE_APPLY (this);
418 hb_buffer_t *buffer = c->buffer;
419 const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
420 unsigned int mark_class = record.klass;
421
422 const Anchor& mark_anchor = this + record.markAnchor;
423 bool found;
424 const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
425 /* If this subtable doesn't have an anchor for this base and this class,
426 * return false such that the subsequent subtables have a chance at it. */
427 if (unlikely (!found)) return_trace (false);
428
429 hb_position_t mark_x, mark_y, base_x, base_y;
430
431 mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
432 glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
433
434 hb_glyph_position_t &o = buffer->cur_pos();
435 o.x_offset = base_x - mark_x;
436 o.y_offset = base_y - mark_y;
437 o.attach_type() = ATTACH_TYPE_MARK;
438 o.attach_chain() = (int) glyph_pos - (int) buffer->idx;
439 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
440
441 buffer->idx++;
442 return_trace (true);
443 }
444
sanitizeOT::MarkArray445 inline bool sanitize (hb_sanitize_context_t *c) const
446 {
447 TRACE_SANITIZE (this);
448 return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
449 }
450 };
451
452
453 /* Lookups */
454
455 struct SinglePosFormat1
456 {
collect_glyphsOT::SinglePosFormat1457 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
458 {
459 TRACE_COLLECT_GLYPHS (this);
460 (this+coverage).add_coverage (c->input);
461 }
462
get_coverageOT::SinglePosFormat1463 inline const Coverage &get_coverage (void) const
464 {
465 return this+coverage;
466 }
467
applyOT::SinglePosFormat1468 inline bool apply (hb_apply_context_t *c) const
469 {
470 TRACE_APPLY (this);
471 hb_buffer_t *buffer = c->buffer;
472 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
473 if (likely (index == NOT_COVERED)) return_trace (false);
474
475 valueFormat.apply_value (c->font, c->direction, this,
476 values, buffer->cur_pos());
477
478 buffer->idx++;
479 return_trace (true);
480 }
481
sanitizeOT::SinglePosFormat1482 inline bool sanitize (hb_sanitize_context_t *c) const
483 {
484 TRACE_SANITIZE (this);
485 return_trace (c->check_struct (this) &&
486 coverage.sanitize (c, this) &&
487 valueFormat.sanitize_value (c, this, values));
488 }
489
490 protected:
491 USHORT format; /* Format identifier--format = 1 */
492 OffsetTo<Coverage>
493 coverage; /* Offset to Coverage table--from
494 * beginning of subtable */
495 ValueFormat valueFormat; /* Defines the types of data in the
496 * ValueRecord */
497 ValueRecord values; /* Defines positioning
498 * value(s)--applied to all glyphs in
499 * the Coverage table */
500 public:
501 DEFINE_SIZE_ARRAY (6, values);
502 };
503
504 struct SinglePosFormat2
505 {
collect_glyphsOT::SinglePosFormat2506 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
507 {
508 TRACE_COLLECT_GLYPHS (this);
509 (this+coverage).add_coverage (c->input);
510 }
511
get_coverageOT::SinglePosFormat2512 inline const Coverage &get_coverage (void) const
513 {
514 return this+coverage;
515 }
516
applyOT::SinglePosFormat2517 inline bool apply (hb_apply_context_t *c) const
518 {
519 TRACE_APPLY (this);
520 hb_buffer_t *buffer = c->buffer;
521 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
522 if (likely (index == NOT_COVERED)) return_trace (false);
523
524 if (likely (index >= valueCount)) return_trace (false);
525
526 valueFormat.apply_value (c->font, c->direction, this,
527 &values[index * valueFormat.get_len ()],
528 buffer->cur_pos());
529
530 buffer->idx++;
531 return_trace (true);
532 }
533
sanitizeOT::SinglePosFormat2534 inline bool sanitize (hb_sanitize_context_t *c) const
535 {
536 TRACE_SANITIZE (this);
537 return_trace (c->check_struct (this) &&
538 coverage.sanitize (c, this) &&
539 valueFormat.sanitize_values (c, this, values, valueCount));
540 }
541
542 protected:
543 USHORT format; /* Format identifier--format = 2 */
544 OffsetTo<Coverage>
545 coverage; /* Offset to Coverage table--from
546 * beginning of subtable */
547 ValueFormat valueFormat; /* Defines the types of data in the
548 * ValueRecord */
549 USHORT valueCount; /* Number of ValueRecords */
550 ValueRecord values; /* Array of ValueRecords--positioning
551 * values applied to glyphs */
552 public:
553 DEFINE_SIZE_ARRAY (8, values);
554 };
555
556 struct SinglePos
557 {
558 template <typename context_t>
dispatchOT::SinglePos559 inline typename context_t::return_t dispatch (context_t *c) const
560 {
561 TRACE_DISPATCH (this, u.format);
562 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
563 switch (u.format) {
564 case 1: return_trace (c->dispatch (u.format1));
565 case 2: return_trace (c->dispatch (u.format2));
566 default:return_trace (c->default_return_value ());
567 }
568 }
569
570 protected:
571 union {
572 USHORT format; /* Format identifier */
573 SinglePosFormat1 format1;
574 SinglePosFormat2 format2;
575 } u;
576 };
577
578
579 struct PairValueRecord
580 {
581 friend struct PairSet;
582
583 protected:
584 GlyphID secondGlyph; /* GlyphID of second glyph in the
585 * pair--first glyph is listed in the
586 * Coverage table */
587 ValueRecord values; /* Positioning data for the first glyph
588 * followed by for second glyph */
589 public:
590 DEFINE_SIZE_ARRAY (2, values);
591 };
592
593 struct PairSet
594 {
595 friend struct PairPosFormat1;
596
collect_glyphsOT::PairSet597 inline void collect_glyphs (hb_collect_glyphs_context_t *c,
598 const ValueFormat *valueFormats) const
599 {
600 TRACE_COLLECT_GLYPHS (this);
601 unsigned int len1 = valueFormats[0].get_len ();
602 unsigned int len2 = valueFormats[1].get_len ();
603 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
604
605 const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
606 unsigned int count = len;
607 for (unsigned int i = 0; i < count; i++)
608 {
609 c->input->add (record->secondGlyph);
610 record = &StructAtOffset<PairValueRecord> (record, record_size);
611 }
612 }
613
applyOT::PairSet614 inline bool apply (hb_apply_context_t *c,
615 const ValueFormat *valueFormats,
616 unsigned int pos) const
617 {
618 TRACE_APPLY (this);
619 hb_buffer_t *buffer = c->buffer;
620 unsigned int len1 = valueFormats[0].get_len ();
621 unsigned int len2 = valueFormats[1].get_len ();
622 unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
623
624 const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
625 unsigned int count = len;
626
627 /* Hand-coded bsearch. */
628 if (unlikely (!count))
629 return_trace (false);
630 hb_codepoint_t x = buffer->info[pos].codepoint;
631 int min = 0, max = (int) count - 1;
632 while (min <= max)
633 {
634 int mid = (min + max) / 2;
635 const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
636 hb_codepoint_t mid_x = record->secondGlyph;
637 if (x < mid_x)
638 max = mid - 1;
639 else if (x > mid_x)
640 min = mid + 1;
641 else
642 {
643 valueFormats[0].apply_value (c->font, c->direction, this,
644 &record->values[0], buffer->cur_pos());
645 valueFormats[1].apply_value (c->font, c->direction, this,
646 &record->values[len1], buffer->pos[pos]);
647 if (len2)
648 pos++;
649 buffer->idx = pos;
650 return_trace (true);
651 }
652 }
653
654 return_trace (false);
655 }
656
657 struct sanitize_closure_t {
658 const void *base;
659 const ValueFormat *valueFormats;
660 unsigned int len1; /* valueFormats[0].get_len() */
661 unsigned int stride; /* 1 + len1 + len2 */
662 };
663
sanitizeOT::PairSet664 inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
665 {
666 TRACE_SANITIZE (this);
667 if (!(c->check_struct (this)
668 && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false);
669
670 unsigned int count = len;
671 const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
672 return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
673 closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
674 }
675
676 protected:
677 USHORT len; /* Number of PairValueRecords */
678 USHORT arrayZ[VAR]; /* Array of PairValueRecords--ordered
679 * by GlyphID of the second glyph */
680 public:
681 DEFINE_SIZE_ARRAY (2, arrayZ);
682 };
683
684 struct PairPosFormat1
685 {
collect_glyphsOT::PairPosFormat1686 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
687 {
688 TRACE_COLLECT_GLYPHS (this);
689 (this+coverage).add_coverage (c->input);
690 unsigned int count = pairSet.len;
691 for (unsigned int i = 0; i < count; i++)
692 (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
693 }
694
get_coverageOT::PairPosFormat1695 inline const Coverage &get_coverage (void) const
696 {
697 return this+coverage;
698 }
699
applyOT::PairPosFormat1700 inline bool apply (hb_apply_context_t *c) const
701 {
702 TRACE_APPLY (this);
703 hb_buffer_t *buffer = c->buffer;
704 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
705 if (likely (index == NOT_COVERED)) return_trace (false);
706
707 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
708 skippy_iter.reset (buffer->idx, 1);
709 if (!skippy_iter.next ()) return_trace (false);
710
711 return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
712 }
713
sanitizeOT::PairPosFormat1714 inline bool sanitize (hb_sanitize_context_t *c) const
715 {
716 TRACE_SANITIZE (this);
717
718 if (!c->check_struct (this)) return_trace (false);
719
720 unsigned int len1 = valueFormat1.get_len ();
721 unsigned int len2 = valueFormat2.get_len ();
722 PairSet::sanitize_closure_t closure = {
723 this,
724 &valueFormat1,
725 len1,
726 1 + len1 + len2
727 };
728
729 return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
730 }
731
732 protected:
733 USHORT format; /* Format identifier--format = 1 */
734 OffsetTo<Coverage>
735 coverage; /* Offset to Coverage table--from
736 * beginning of subtable */
737 ValueFormat valueFormat1; /* Defines the types of data in
738 * ValueRecord1--for the first glyph
739 * in the pair--may be zero (0) */
740 ValueFormat valueFormat2; /* Defines the types of data in
741 * ValueRecord2--for the second glyph
742 * in the pair--may be zero (0) */
743 OffsetArrayOf<PairSet>
744 pairSet; /* Array of PairSet tables
745 * ordered by Coverage Index */
746 public:
747 DEFINE_SIZE_ARRAY (10, pairSet);
748 };
749
750 struct PairPosFormat2
751 {
collect_glyphsOT::PairPosFormat2752 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
753 {
754 TRACE_COLLECT_GLYPHS (this);
755 (this+coverage).add_coverage (c->input);
756
757 unsigned int count1 = class1Count;
758 const ClassDef &klass1 = this+classDef1;
759 for (unsigned int i = 0; i < count1; i++)
760 klass1.add_class (c->input, i);
761
762 unsigned int count2 = class2Count;
763 const ClassDef &klass2 = this+classDef2;
764 for (unsigned int i = 0; i < count2; i++)
765 klass2.add_class (c->input, i);
766 }
767
get_coverageOT::PairPosFormat2768 inline const Coverage &get_coverage (void) const
769 {
770 return this+coverage;
771 }
772
applyOT::PairPosFormat2773 inline bool apply (hb_apply_context_t *c) const
774 {
775 TRACE_APPLY (this);
776 hb_buffer_t *buffer = c->buffer;
777 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
778 if (likely (index == NOT_COVERED)) return_trace (false);
779
780 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
781 skippy_iter.reset (buffer->idx, 1);
782 if (!skippy_iter.next ()) return_trace (false);
783
784 unsigned int len1 = valueFormat1.get_len ();
785 unsigned int len2 = valueFormat2.get_len ();
786 unsigned int record_len = len1 + len2;
787
788 unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
789 unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
790 if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
791
792 const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
793 valueFormat1.apply_value (c->font, c->direction, this,
794 v, buffer->cur_pos());
795 valueFormat2.apply_value (c->font, c->direction, this,
796 v + len1, buffer->pos[skippy_iter.idx]);
797
798 buffer->idx = skippy_iter.idx;
799 if (len2)
800 buffer->idx++;
801
802 return_trace (true);
803 }
804
sanitizeOT::PairPosFormat2805 inline bool sanitize (hb_sanitize_context_t *c) const
806 {
807 TRACE_SANITIZE (this);
808 if (!(c->check_struct (this)
809 && coverage.sanitize (c, this)
810 && classDef1.sanitize (c, this)
811 && classDef2.sanitize (c, this))) return_trace (false);
812
813 unsigned int len1 = valueFormat1.get_len ();
814 unsigned int len2 = valueFormat2.get_len ();
815 unsigned int stride = len1 + len2;
816 unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
817 unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
818 return_trace (c->check_array (values, record_size, count) &&
819 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
820 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
821 }
822
823 protected:
824 USHORT format; /* Format identifier--format = 2 */
825 OffsetTo<Coverage>
826 coverage; /* Offset to Coverage table--from
827 * beginning of subtable */
828 ValueFormat valueFormat1; /* ValueRecord definition--for the
829 * first glyph of the pair--may be zero
830 * (0) */
831 ValueFormat valueFormat2; /* ValueRecord definition--for the
832 * second glyph of the pair--may be
833 * zero (0) */
834 OffsetTo<ClassDef>
835 classDef1; /* Offset to ClassDef table--from
836 * beginning of PairPos subtable--for
837 * the first glyph of the pair */
838 OffsetTo<ClassDef>
839 classDef2; /* Offset to ClassDef table--from
840 * beginning of PairPos subtable--for
841 * the second glyph of the pair */
842 USHORT class1Count; /* Number of classes in ClassDef1
843 * table--includes Class0 */
844 USHORT class2Count; /* Number of classes in ClassDef2
845 * table--includes Class0 */
846 ValueRecord values; /* Matrix of value pairs:
847 * class1-major, class2-minor,
848 * Each entry has value1 and value2 */
849 public:
850 DEFINE_SIZE_ARRAY (16, values);
851 };
852
853 struct PairPos
854 {
855 template <typename context_t>
dispatchOT::PairPos856 inline typename context_t::return_t dispatch (context_t *c) const
857 {
858 TRACE_DISPATCH (this, u.format);
859 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
860 switch (u.format) {
861 case 1: return_trace (c->dispatch (u.format1));
862 case 2: return_trace (c->dispatch (u.format2));
863 default:return_trace (c->default_return_value ());
864 }
865 }
866
867 protected:
868 union {
869 USHORT format; /* Format identifier */
870 PairPosFormat1 format1;
871 PairPosFormat2 format2;
872 } u;
873 };
874
875
876 struct EntryExitRecord
877 {
878 friend struct CursivePosFormat1;
879
sanitizeOT::EntryExitRecord880 inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
881 {
882 TRACE_SANITIZE (this);
883 return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
884 }
885
886 protected:
887 OffsetTo<Anchor>
888 entryAnchor; /* Offset to EntryAnchor table--from
889 * beginning of CursivePos
890 * subtable--may be NULL */
891 OffsetTo<Anchor>
892 exitAnchor; /* Offset to ExitAnchor table--from
893 * beginning of CursivePos
894 * subtable--may be NULL */
895 public:
896 DEFINE_SIZE_STATIC (4);
897 };
898
899 static void
900 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
901
902 struct CursivePosFormat1
903 {
collect_glyphsOT::CursivePosFormat1904 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
905 {
906 TRACE_COLLECT_GLYPHS (this);
907 (this+coverage).add_coverage (c->input);
908 }
909
get_coverageOT::CursivePosFormat1910 inline const Coverage &get_coverage (void) const
911 {
912 return this+coverage;
913 }
914
applyOT::CursivePosFormat1915 inline bool apply (hb_apply_context_t *c) const
916 {
917 TRACE_APPLY (this);
918 hb_buffer_t *buffer = c->buffer;
919
920 const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
921 if (!this_record.exitAnchor) return_trace (false);
922
923 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
924 skippy_iter.reset (buffer->idx, 1);
925 if (!skippy_iter.next ()) return_trace (false);
926
927 const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
928 if (!next_record.entryAnchor) return_trace (false);
929
930 unsigned int i = buffer->idx;
931 unsigned int j = skippy_iter.idx;
932
933 hb_position_t entry_x, entry_y, exit_x, exit_y;
934 (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
935 (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
936
937 hb_glyph_position_t *pos = buffer->pos;
938
939 hb_position_t d;
940 /* Main-direction adjustment */
941 switch (c->direction) {
942 case HB_DIRECTION_LTR:
943 pos[i].x_advance = exit_x + pos[i].x_offset;
944
945 d = entry_x + pos[j].x_offset;
946 pos[j].x_advance -= d;
947 pos[j].x_offset -= d;
948 break;
949 case HB_DIRECTION_RTL:
950 d = exit_x + pos[i].x_offset;
951 pos[i].x_advance -= d;
952 pos[i].x_offset -= d;
953
954 pos[j].x_advance = entry_x + pos[j].x_offset;
955 break;
956 case HB_DIRECTION_TTB:
957 pos[i].y_advance = exit_y + pos[i].y_offset;
958
959 d = entry_y + pos[j].y_offset;
960 pos[j].y_advance -= d;
961 pos[j].y_offset -= d;
962 break;
963 case HB_DIRECTION_BTT:
964 d = exit_y + pos[i].y_offset;
965 pos[i].y_advance -= d;
966 pos[i].y_offset -= d;
967
968 pos[j].y_advance = entry_y;
969 break;
970 case HB_DIRECTION_INVALID:
971 default:
972 break;
973 }
974
975 /* Cross-direction adjustment */
976
977 /* We attach child to parent (think graph theory and rooted trees whereas
978 * the root stays on baseline and each node aligns itself against its
979 * parent.
980 *
981 * Optimize things for the case of RightToLeft, as that's most common in
982 * Arabinc. */
983 unsigned int child = i;
984 unsigned int parent = j;
985 hb_position_t x_offset = entry_x - exit_x;
986 hb_position_t y_offset = entry_y - exit_y;
987 if (!(c->lookup_props & LookupFlag::RightToLeft))
988 {
989 unsigned int k = child;
990 child = parent;
991 parent = k;
992 x_offset = -x_offset;
993 y_offset = -y_offset;
994 }
995
996 /* If child was already connected to someone else, walk through its old
997 * chain and reverse the link direction, such that the whole tree of its
998 * previous connection now attaches to new parent. Watch out for case
999 * where new parent is on the path from old chain...
1000 */
1001 reverse_cursive_minor_offset (pos, child, c->direction, parent);
1002
1003 pos[child].attach_type() = ATTACH_TYPE_CURSIVE;
1004 pos[child].attach_chain() = (int) parent - (int) child;
1005 buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
1006 if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
1007 pos[child].y_offset = y_offset;
1008 else
1009 pos[child].x_offset = x_offset;
1010
1011 buffer->idx = j;
1012 return_trace (true);
1013 }
1014
sanitizeOT::CursivePosFormat11015 inline bool sanitize (hb_sanitize_context_t *c) const
1016 {
1017 TRACE_SANITIZE (this);
1018 return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
1019 }
1020
1021 protected:
1022 USHORT format; /* Format identifier--format = 1 */
1023 OffsetTo<Coverage>
1024 coverage; /* Offset to Coverage table--from
1025 * beginning of subtable */
1026 ArrayOf<EntryExitRecord>
1027 entryExitRecord; /* Array of EntryExit records--in
1028 * Coverage Index order */
1029 public:
1030 DEFINE_SIZE_ARRAY (6, entryExitRecord);
1031 };
1032
1033 struct CursivePos
1034 {
1035 template <typename context_t>
dispatchOT::CursivePos1036 inline typename context_t::return_t dispatch (context_t *c) const
1037 {
1038 TRACE_DISPATCH (this, u.format);
1039 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1040 switch (u.format) {
1041 case 1: return_trace (c->dispatch (u.format1));
1042 default:return_trace (c->default_return_value ());
1043 }
1044 }
1045
1046 protected:
1047 union {
1048 USHORT format; /* Format identifier */
1049 CursivePosFormat1 format1;
1050 } u;
1051 };
1052
1053
1054 typedef AnchorMatrix BaseArray; /* base-major--
1055 * in order of BaseCoverage Index--,
1056 * mark-minor--
1057 * ordered by class--zero-based. */
1058
1059 struct MarkBasePosFormat1
1060 {
collect_glyphsOT::MarkBasePosFormat11061 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1062 {
1063 TRACE_COLLECT_GLYPHS (this);
1064 (this+markCoverage).add_coverage (c->input);
1065 (this+baseCoverage).add_coverage (c->input);
1066 }
1067
get_coverageOT::MarkBasePosFormat11068 inline const Coverage &get_coverage (void) const
1069 {
1070 return this+markCoverage;
1071 }
1072
applyOT::MarkBasePosFormat11073 inline bool apply (hb_apply_context_t *c) const
1074 {
1075 TRACE_APPLY (this);
1076 hb_buffer_t *buffer = c->buffer;
1077 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
1078 if (likely (mark_index == NOT_COVERED)) return_trace (false);
1079
1080 /* Now we search backwards for a non-mark glyph */
1081 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1082 skippy_iter.reset (buffer->idx, 1);
1083 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1084 do {
1085 if (!skippy_iter.prev ()) return_trace (false);
1086 /* We only want to attach to the first of a MultipleSubst sequence. Reject others. */
1087 if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
1088 skippy_iter.reject ();
1089 } while (1);
1090
1091 /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
1092 //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1093
1094 unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint);
1095 if (base_index == NOT_COVERED) return_trace (false);
1096
1097 return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
1098 }
1099
sanitizeOT::MarkBasePosFormat11100 inline bool sanitize (hb_sanitize_context_t *c) const
1101 {
1102 TRACE_SANITIZE (this);
1103 return_trace (c->check_struct (this) &&
1104 markCoverage.sanitize (c, this) &&
1105 baseCoverage.sanitize (c, this) &&
1106 markArray.sanitize (c, this) &&
1107 baseArray.sanitize (c, this, (unsigned int) classCount));
1108 }
1109
1110 protected:
1111 USHORT format; /* Format identifier--format = 1 */
1112 OffsetTo<Coverage>
1113 markCoverage; /* Offset to MarkCoverage table--from
1114 * beginning of MarkBasePos subtable */
1115 OffsetTo<Coverage>
1116 baseCoverage; /* Offset to BaseCoverage table--from
1117 * beginning of MarkBasePos subtable */
1118 USHORT classCount; /* Number of classes defined for marks */
1119 OffsetTo<MarkArray>
1120 markArray; /* Offset to MarkArray table--from
1121 * beginning of MarkBasePos subtable */
1122 OffsetTo<BaseArray>
1123 baseArray; /* Offset to BaseArray table--from
1124 * beginning of MarkBasePos subtable */
1125 public:
1126 DEFINE_SIZE_STATIC (12);
1127 };
1128
1129 struct MarkBasePos
1130 {
1131 template <typename context_t>
dispatchOT::MarkBasePos1132 inline typename context_t::return_t dispatch (context_t *c) const
1133 {
1134 TRACE_DISPATCH (this, u.format);
1135 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1136 switch (u.format) {
1137 case 1: return_trace (c->dispatch (u.format1));
1138 default:return_trace (c->default_return_value ());
1139 }
1140 }
1141
1142 protected:
1143 union {
1144 USHORT format; /* Format identifier */
1145 MarkBasePosFormat1 format1;
1146 } u;
1147 };
1148
1149
1150 typedef AnchorMatrix LigatureAttach; /* component-major--
1151 * in order of writing direction--,
1152 * mark-minor--
1153 * ordered by class--zero-based. */
1154
1155 typedef OffsetListOf<LigatureAttach> LigatureArray;
1156 /* Array of LigatureAttach
1157 * tables ordered by
1158 * LigatureCoverage Index */
1159
1160 struct MarkLigPosFormat1
1161 {
collect_glyphsOT::MarkLigPosFormat11162 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1163 {
1164 TRACE_COLLECT_GLYPHS (this);
1165 (this+markCoverage).add_coverage (c->input);
1166 (this+ligatureCoverage).add_coverage (c->input);
1167 }
1168
get_coverageOT::MarkLigPosFormat11169 inline const Coverage &get_coverage (void) const
1170 {
1171 return this+markCoverage;
1172 }
1173
applyOT::MarkLigPosFormat11174 inline bool apply (hb_apply_context_t *c) const
1175 {
1176 TRACE_APPLY (this);
1177 hb_buffer_t *buffer = c->buffer;
1178 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint);
1179 if (likely (mark_index == NOT_COVERED)) return_trace (false);
1180
1181 /* Now we search backwards for a non-mark glyph */
1182 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1183 skippy_iter.reset (buffer->idx, 1);
1184 skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
1185 if (!skippy_iter.prev ()) return_trace (false);
1186
1187 /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
1188 //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1189
1190 unsigned int j = skippy_iter.idx;
1191 unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint);
1192 if (lig_index == NOT_COVERED) return_trace (false);
1193
1194 const LigatureArray& lig_array = this+ligatureArray;
1195 const LigatureAttach& lig_attach = lig_array[lig_index];
1196
1197 /* Find component to attach to */
1198 unsigned int comp_count = lig_attach.rows;
1199 if (unlikely (!comp_count)) return_trace (false);
1200
1201 /* We must now check whether the ligature ID of the current mark glyph
1202 * is identical to the ligature ID of the found ligature. If yes, we
1203 * can directly use the component index. If not, we attach the mark
1204 * glyph to the last component of the ligature. */
1205 unsigned int comp_index;
1206 unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1207 unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1208 unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
1209 if (lig_id && lig_id == mark_id && mark_comp > 0)
1210 comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
1211 else
1212 comp_index = comp_count - 1;
1213
1214 return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
1215 }
1216
sanitizeOT::MarkLigPosFormat11217 inline bool sanitize (hb_sanitize_context_t *c) const
1218 {
1219 TRACE_SANITIZE (this);
1220 return_trace (c->check_struct (this) &&
1221 markCoverage.sanitize (c, this) &&
1222 ligatureCoverage.sanitize (c, this) &&
1223 markArray.sanitize (c, this) &&
1224 ligatureArray.sanitize (c, this, (unsigned int) classCount));
1225 }
1226
1227 protected:
1228 USHORT format; /* Format identifier--format = 1 */
1229 OffsetTo<Coverage>
1230 markCoverage; /* Offset to Mark Coverage table--from
1231 * beginning of MarkLigPos subtable */
1232 OffsetTo<Coverage>
1233 ligatureCoverage; /* Offset to Ligature Coverage
1234 * table--from beginning of MarkLigPos
1235 * subtable */
1236 USHORT classCount; /* Number of defined mark classes */
1237 OffsetTo<MarkArray>
1238 markArray; /* Offset to MarkArray table--from
1239 * beginning of MarkLigPos subtable */
1240 OffsetTo<LigatureArray>
1241 ligatureArray; /* Offset to LigatureArray table--from
1242 * beginning of MarkLigPos subtable */
1243 public:
1244 DEFINE_SIZE_STATIC (12);
1245 };
1246
1247 struct MarkLigPos
1248 {
1249 template <typename context_t>
dispatchOT::MarkLigPos1250 inline typename context_t::return_t dispatch (context_t *c) const
1251 {
1252 TRACE_DISPATCH (this, u.format);
1253 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1254 switch (u.format) {
1255 case 1: return_trace (c->dispatch (u.format1));
1256 default:return_trace (c->default_return_value ());
1257 }
1258 }
1259
1260 protected:
1261 union {
1262 USHORT format; /* Format identifier */
1263 MarkLigPosFormat1 format1;
1264 } u;
1265 };
1266
1267
1268 typedef AnchorMatrix Mark2Array; /* mark2-major--
1269 * in order of Mark2Coverage Index--,
1270 * mark1-minor--
1271 * ordered by class--zero-based. */
1272
1273 struct MarkMarkPosFormat1
1274 {
collect_glyphsOT::MarkMarkPosFormat11275 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1276 {
1277 TRACE_COLLECT_GLYPHS (this);
1278 (this+mark1Coverage).add_coverage (c->input);
1279 (this+mark2Coverage).add_coverage (c->input);
1280 }
1281
get_coverageOT::MarkMarkPosFormat11282 inline const Coverage &get_coverage (void) const
1283 {
1284 return this+mark1Coverage;
1285 }
1286
applyOT::MarkMarkPosFormat11287 inline bool apply (hb_apply_context_t *c) const
1288 {
1289 TRACE_APPLY (this);
1290 hb_buffer_t *buffer = c->buffer;
1291 unsigned int mark1_index = (this+mark1Coverage).get_coverage (buffer->cur().codepoint);
1292 if (likely (mark1_index == NOT_COVERED)) return_trace (false);
1293
1294 /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1295 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
1296 skippy_iter.reset (buffer->idx, 1);
1297 skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
1298 if (!skippy_iter.prev ()) return_trace (false);
1299
1300 if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
1301
1302 unsigned int j = skippy_iter.idx;
1303
1304 unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
1305 unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
1306 unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
1307 unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
1308
1309 if (likely (id1 == id2)) {
1310 if (id1 == 0) /* Marks belonging to the same base. */
1311 goto good;
1312 else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
1313 goto good;
1314 } else {
1315 /* If ligature ids don't match, it may be the case that one of the marks
1316 * itself is a ligature. In which case match. */
1317 if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
1318 goto good;
1319 }
1320
1321 /* Didn't match. */
1322 return_trace (false);
1323
1324 good:
1325 unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint);
1326 if (mark2_index == NOT_COVERED) return_trace (false);
1327
1328 return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
1329 }
1330
sanitizeOT::MarkMarkPosFormat11331 inline bool sanitize (hb_sanitize_context_t *c) const
1332 {
1333 TRACE_SANITIZE (this);
1334 return_trace (c->check_struct (this) &&
1335 mark1Coverage.sanitize (c, this) &&
1336 mark2Coverage.sanitize (c, this) &&
1337 mark1Array.sanitize (c, this) &&
1338 mark2Array.sanitize (c, this, (unsigned int) classCount));
1339 }
1340
1341 protected:
1342 USHORT format; /* Format identifier--format = 1 */
1343 OffsetTo<Coverage>
1344 mark1Coverage; /* Offset to Combining Mark1 Coverage
1345 * table--from beginning of MarkMarkPos
1346 * subtable */
1347 OffsetTo<Coverage>
1348 mark2Coverage; /* Offset to Combining Mark2 Coverage
1349 * table--from beginning of MarkMarkPos
1350 * subtable */
1351 USHORT classCount; /* Number of defined mark classes */
1352 OffsetTo<MarkArray>
1353 mark1Array; /* Offset to Mark1Array table--from
1354 * beginning of MarkMarkPos subtable */
1355 OffsetTo<Mark2Array>
1356 mark2Array; /* Offset to Mark2Array table--from
1357 * beginning of MarkMarkPos subtable */
1358 public:
1359 DEFINE_SIZE_STATIC (12);
1360 };
1361
1362 struct MarkMarkPos
1363 {
1364 template <typename context_t>
dispatchOT::MarkMarkPos1365 inline typename context_t::return_t dispatch (context_t *c) const
1366 {
1367 TRACE_DISPATCH (this, u.format);
1368 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1369 switch (u.format) {
1370 case 1: return_trace (c->dispatch (u.format1));
1371 default:return_trace (c->default_return_value ());
1372 }
1373 }
1374
1375 protected:
1376 union {
1377 USHORT format; /* Format identifier */
1378 MarkMarkPosFormat1 format1;
1379 } u;
1380 };
1381
1382
1383 struct ContextPos : Context {};
1384
1385 struct ChainContextPos : ChainContext {};
1386
1387 struct ExtensionPos : Extension<ExtensionPos>
1388 {
1389 typedef struct PosLookupSubTable LookupSubTable;
1390 };
1391
1392
1393
1394 /*
1395 * PosLookup
1396 */
1397
1398
1399 struct PosLookupSubTable
1400 {
1401 friend struct PosLookup;
1402
1403 enum Type {
1404 Single = 1,
1405 Pair = 2,
1406 Cursive = 3,
1407 MarkBase = 4,
1408 MarkLig = 5,
1409 MarkMark = 6,
1410 Context = 7,
1411 ChainContext = 8,
1412 Extension = 9
1413 };
1414
1415 template <typename context_t>
dispatchOT::PosLookupSubTable1416 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1417 {
1418 TRACE_DISPATCH (this, lookup_type);
1419 if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1420 switch (lookup_type) {
1421 case Single: return_trace (u.single.dispatch (c));
1422 case Pair: return_trace (u.pair.dispatch (c));
1423 case Cursive: return_trace (u.cursive.dispatch (c));
1424 case MarkBase: return_trace (u.markBase.dispatch (c));
1425 case MarkLig: return_trace (u.markLig.dispatch (c));
1426 case MarkMark: return_trace (u.markMark.dispatch (c));
1427 case Context: return_trace (u.context.dispatch (c));
1428 case ChainContext: return_trace (u.chainContext.dispatch (c));
1429 case Extension: return_trace (u.extension.dispatch (c));
1430 default: return_trace (c->default_return_value ());
1431 }
1432 }
1433
1434 protected:
1435 union {
1436 USHORT sub_format;
1437 SinglePos single;
1438 PairPos pair;
1439 CursivePos cursive;
1440 MarkBasePos markBase;
1441 MarkLigPos markLig;
1442 MarkMarkPos markMark;
1443 ContextPos context;
1444 ChainContextPos chainContext;
1445 ExtensionPos extension;
1446 } u;
1447 public:
1448 DEFINE_SIZE_UNION (2, sub_format);
1449 };
1450
1451
1452 struct PosLookup : Lookup
1453 {
get_subtableOT::PosLookup1454 inline const PosLookupSubTable& get_subtable (unsigned int i) const
1455 { return Lookup::get_subtable<PosLookupSubTable> (i); }
1456
is_reverseOT::PosLookup1457 inline bool is_reverse (void) const
1458 {
1459 return false;
1460 }
1461
applyOT::PosLookup1462 inline bool apply (hb_apply_context_t *c) const
1463 {
1464 TRACE_APPLY (this);
1465 return_trace (dispatch (c));
1466 }
1467
collect_glyphsOT::PosLookup1468 inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
1469 {
1470 TRACE_COLLECT_GLYPHS (this);
1471 return_trace (dispatch (c));
1472 }
1473
1474 template <typename set_t>
add_coverageOT::PosLookup1475 inline void add_coverage (set_t *glyphs) const
1476 {
1477 hb_add_coverage_context_t<set_t> c (glyphs);
1478 dispatch (&c);
1479 }
1480
1481 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
1482
1483 template <typename context_t>
1484 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
1485
1486 template <typename context_t>
dispatchOT::PosLookup1487 inline typename context_t::return_t dispatch (context_t *c) const
1488 { return Lookup::dispatch<PosLookupSubTable> (c); }
1489
sanitizeOT::PosLookup1490 inline bool sanitize (hb_sanitize_context_t *c) const
1491 {
1492 TRACE_SANITIZE (this);
1493 if (unlikely (!Lookup::sanitize (c))) return_trace (false);
1494 return_trace (dispatch (c));
1495 }
1496 };
1497
1498 typedef OffsetListOf<PosLookup> PosLookupList;
1499
1500 /*
1501 * GPOS -- The Glyph Positioning Table
1502 */
1503
1504 struct GPOS : GSUBGPOS
1505 {
1506 static const hb_tag_t tableTag = HB_OT_TAG_GPOS;
1507
get_lookupOT::GPOS1508 inline const PosLookup& get_lookup (unsigned int i) const
1509 { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1510
1511 static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
1512 static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer);
1513 static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer);
1514
sanitizeOT::GPOS1515 inline bool sanitize (hb_sanitize_context_t *c) const
1516 {
1517 TRACE_SANITIZE (this);
1518 if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
1519 const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1520 return_trace (list.sanitize (c, this));
1521 }
1522 public:
1523 DEFINE_SIZE_STATIC (10);
1524 };
1525
1526
1527 static void
reverse_cursive_minor_offset(hb_glyph_position_t * pos,unsigned int i,hb_direction_t direction,unsigned int new_parent)1528 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
1529 {
1530 int chain = pos[i].attach_chain(), type = pos[i].attach_type();
1531 if (likely (!chain || 0 == (type & ATTACH_TYPE_CURSIVE)))
1532 return;
1533
1534 pos[i].attach_chain() = 0;
1535
1536 unsigned int j = (int) i + chain;
1537
1538 /* Stop if we see new parent in the chain. */
1539 if (j == new_parent)
1540 return;
1541
1542 reverse_cursive_minor_offset (pos, j, direction, new_parent);
1543
1544 if (HB_DIRECTION_IS_HORIZONTAL (direction))
1545 pos[j].y_offset = -pos[i].y_offset;
1546 else
1547 pos[j].x_offset = -pos[i].x_offset;
1548
1549 pos[j].attach_chain() = -chain;
1550 pos[j].attach_type() = type;
1551 }
1552 static void
propagate_attachment_offsets(hb_glyph_position_t * pos,unsigned int i,hb_direction_t direction)1553 propagate_attachment_offsets (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1554 {
1555 /* Adjusts offsets of attached glyphs (both cursive and mark) to accumulate
1556 * offset of glyph they are attached to. */
1557 int chain = pos[i].attach_chain(), type = pos[i].attach_type();
1558 if (likely (!chain))
1559 return;
1560
1561 unsigned int j = (int) i + chain;
1562
1563 pos[i].attach_chain() = 0;
1564
1565 propagate_attachment_offsets (pos, j, direction);
1566
1567 assert (!!(type & ATTACH_TYPE_MARK) ^ !!(type & ATTACH_TYPE_CURSIVE));
1568
1569 if (type & ATTACH_TYPE_CURSIVE)
1570 {
1571 if (HB_DIRECTION_IS_HORIZONTAL (direction))
1572 pos[i].y_offset += pos[j].y_offset;
1573 else
1574 pos[i].x_offset += pos[j].x_offset;
1575 }
1576 else /*if (type & ATTACH_TYPE_MARK)*/
1577 {
1578 pos[i].x_offset += pos[j].x_offset;
1579 pos[i].y_offset += pos[j].y_offset;
1580
1581 assert (j < i);
1582 if (HB_DIRECTION_IS_FORWARD (direction))
1583 for (unsigned int k = j; k < i; k++) {
1584 pos[i].x_offset -= pos[k].x_advance;
1585 pos[i].y_offset -= pos[k].y_advance;
1586 }
1587 else
1588 for (unsigned int k = j + 1; k < i + 1; k++) {
1589 pos[i].x_offset += pos[k].x_advance;
1590 pos[i].y_offset += pos[k].y_advance;
1591 }
1592 }
1593 }
1594
1595 void
position_start(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1596 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1597 {
1598 unsigned int count = buffer->len;
1599 for (unsigned int i = 0; i < count; i++)
1600 buffer->pos[i].attach_chain() = buffer->pos[i].attach_type() = 0;
1601 }
1602
1603 void
position_finish_advances(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1604 GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1605 {
1606 //_hb_buffer_assert_gsubgpos_vars (buffer);
1607 }
1608
1609 void
position_finish_offsets(hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)1610 GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
1611 {
1612 _hb_buffer_assert_gsubgpos_vars (buffer);
1613
1614 unsigned int len;
1615 hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1616 hb_direction_t direction = buffer->props.direction;
1617
1618 /* Handle attachments */
1619 if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT)
1620 for (unsigned int i = 0; i < len; i++)
1621 propagate_attachment_offsets (pos, i, direction);
1622 }
1623
1624
1625 /* Out-of-class implementation for methods recursing */
1626
1627 template <typename context_t>
dispatch_recurse_func(context_t * c,unsigned int lookup_index)1628 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1629 {
1630 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
1631 const PosLookup &l = gpos.get_lookup (lookup_index);
1632 return l.dispatch (c);
1633 }
1634
apply_recurse_func(hb_apply_context_t * c,unsigned int lookup_index)1635 /*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
1636 {
1637 const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
1638 const PosLookup &l = gpos.get_lookup (lookup_index);
1639 unsigned int saved_lookup_props = c->lookup_props;
1640 unsigned int saved_lookup_index = c->lookup_index;
1641 c->set_lookup_index (lookup_index);
1642 c->set_lookup_props (l.get_props ());
1643 bool ret = l.dispatch (c);
1644 c->set_lookup_index (saved_lookup_index);
1645 c->set_lookup_props (saved_lookup_props);
1646 return ret;
1647 }
1648
1649
1650 #undef attach_chain
1651 #undef attach_type
1652
1653
1654 } /* namespace OT */
1655
1656
1657 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
1658