1 : /*
2 : * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 : * Copyright © 2010 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 :
36 : /* buffer **position** var allocations */
37 : #define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
38 : #define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
39 :
40 :
41 : /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
42 :
43 : typedef USHORT Value;
44 :
45 : typedef Value ValueRecord[VAR];
46 :
47 : struct ValueFormat : USHORT
48 : {
49 : enum
50 : {
51 : xPlacement = 0x0001, /* Includes horizontal adjustment for placement */
52 : yPlacement = 0x0002, /* Includes vertical adjustment for placement */
53 : xAdvance = 0x0004, /* Includes horizontal adjustment for advance */
54 : yAdvance = 0x0008, /* Includes vertical adjustment for advance */
55 : xPlaDevice = 0x0010, /* Includes horizontal Device table for placement */
56 : yPlaDevice = 0x0020, /* Includes vertical Device table for placement */
57 : xAdvDevice = 0x0040, /* Includes horizontal Device table for advance */
58 : yAdvDevice = 0x0080, /* Includes vertical Device table for advance */
59 : ignored = 0x0F00, /* Was used in TrueType Open for MM fonts */
60 : reserved = 0xF000, /* For future use */
61 :
62 : devices = 0x00F0 /* Mask for having any Device table */
63 : };
64 :
65 : /* All fields are options. Only those available advance the value pointer. */
66 : #if 0
67 : SHORT xPlacement; /* Horizontal adjustment for
68 : * placement--in design units */
69 : SHORT yPlacement; /* Vertical adjustment for
70 : * placement--in design units */
71 : SHORT xAdvance; /* Horizontal adjustment for
72 : * advance--in design units (only used
73 : * for horizontal writing) */
74 : SHORT yAdvance; /* Vertical adjustment for advance--in
75 : * design units (only used for vertical
76 : * writing) */
77 : Offset xPlaDevice; /* Offset to Device table for
78 : * horizontal placement--measured from
79 : * beginning of PosTable (may be NULL) */
80 : Offset yPlaDevice; /* Offset to Device table for vertical
81 : * placement--measured from beginning
82 : * of PosTable (may be NULL) */
83 : Offset xAdvDevice; /* Offset to Device table for
84 : * horizontal advance--measured from
85 : * beginning of PosTable (may be NULL) */
86 : Offset yAdvDevice; /* Offset to Device table for vertical
87 : * advance--measured from beginning of
88 : * PosTable (may be NULL) */
89 : #endif
90 :
91 0 : inline unsigned int get_len (void) const
92 0 : { return _hb_popcount32 ((unsigned int) *this); }
93 0 : inline unsigned int get_size (void) const
94 0 : { return get_len () * Value::static_size; }
95 :
96 0 : void apply_value (hb_font_t *font,
97 : hb_direction_t direction,
98 : const void *base,
99 : const Value *values,
100 : hb_glyph_position_t &glyph_pos) const
101 : {
102 : unsigned int x_ppem, y_ppem;
103 0 : unsigned int format = *this;
104 0 : hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
105 :
106 0 : if (!format) return;
107 :
108 0 : if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++));
109 0 : if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++));
110 0 : if (format & xAdvance) {
111 0 : if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values++)); else values++;
112 : }
113 : /* y_advance values grow downward but font-space grows upward, hence negation */
114 0 : if (format & yAdvance) {
115 0 : if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values++)); else values++;
116 : }
117 :
118 0 : if (!has_device ()) return;
119 :
120 0 : x_ppem = font->x_ppem;
121 0 : y_ppem = font->y_ppem;
122 :
123 0 : if (!x_ppem && !y_ppem) return;
124 :
125 : /* pixel -> fractional pixel */
126 0 : if (format & xPlaDevice) {
127 0 : if (x_ppem) glyph_pos.x_offset += (base + get_device (values++)).get_x_delta (font); else values++;
128 : }
129 0 : if (format & yPlaDevice) {
130 0 : if (y_ppem) glyph_pos.y_offset += (base + get_device (values++)).get_y_delta (font); else values++;
131 : }
132 0 : if (format & xAdvDevice) {
133 0 : if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values++)).get_x_delta (font); else values++;
134 : }
135 0 : if (format & yAdvDevice) {
136 : /* y_advance values grow downward but font-space grows upward, hence negation */
137 0 : if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values++)).get_y_delta (font); else values++;
138 : }
139 : }
140 :
141 : private:
142 0 : inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
143 0 : unsigned int format = *this;
144 :
145 0 : if (format & xPlacement) values++;
146 0 : if (format & yPlacement) values++;
147 0 : if (format & xAdvance) values++;
148 0 : if (format & yAdvance) values++;
149 :
150 0 : if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
151 0 : if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
152 0 : if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
153 0 : if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
154 :
155 0 : return true;
156 : }
157 :
158 0 : static inline OffsetTo<Device>& get_device (Value* value)
159 0 : { return *CastP<OffsetTo<Device> > (value); }
160 0 : static inline const OffsetTo<Device>& get_device (const Value* value)
161 0 : { return *CastP<OffsetTo<Device> > (value); }
162 :
163 0 : static inline const SHORT& get_short (const Value* value)
164 0 : { return *CastP<SHORT> (value); }
165 :
166 : public:
167 :
168 0 : inline bool has_device (void) const {
169 0 : unsigned int format = *this;
170 0 : return (format & devices) != 0;
171 : }
172 :
173 0 : inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
174 0 : TRACE_SANITIZE ();
175 0 : return c->check_range (values, get_size ())
176 0 : && (!has_device () || sanitize_value_devices (c, base, values));
177 : }
178 :
179 0 : inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
180 0 : TRACE_SANITIZE ();
181 0 : unsigned int len = get_len ();
182 :
183 0 : if (!c->check_array (values, get_size (), count)) return false;
184 :
185 0 : if (!has_device ()) return true;
186 :
187 0 : for (unsigned int i = 0; i < count; i++) {
188 0 : if (!sanitize_value_devices (c, base, values))
189 0 : return false;
190 0 : values += len;
191 : }
192 :
193 0 : return true;
194 : }
195 :
196 : /* Just sanitize referenced Device tables. Doesn't check the values themselves. */
197 0 : inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
198 0 : TRACE_SANITIZE ();
199 :
200 0 : if (!has_device ()) return true;
201 :
202 0 : for (unsigned int i = 0; i < count; i++) {
203 0 : if (!sanitize_value_devices (c, base, values))
204 0 : return false;
205 0 : values += stride;
206 : }
207 :
208 0 : return true;
209 : }
210 : };
211 :
212 :
213 : struct AnchorFormat1
214 : {
215 : friend struct Anchor;
216 :
217 : private:
218 0 : inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
219 : hb_position_t *x, hb_position_t *y) const
220 : {
221 0 : *x = font->em_scale_x (xCoordinate);
222 0 : *y = font->em_scale_y (yCoordinate);
223 0 : }
224 :
225 0 : inline bool sanitize (hb_sanitize_context_t *c) {
226 0 : TRACE_SANITIZE ();
227 0 : return c->check_struct (this);
228 : }
229 :
230 : private:
231 : USHORT format; /* Format identifier--format = 1 */
232 : SHORT xCoordinate; /* Horizontal value--in design units */
233 : SHORT yCoordinate; /* Vertical value--in design units */
234 : public:
235 : DEFINE_SIZE_STATIC (6);
236 : };
237 :
238 : struct AnchorFormat2
239 : {
240 : friend struct Anchor;
241 :
242 : private:
243 0 : inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
244 : hb_position_t *x, hb_position_t *y) const
245 : {
246 0 : unsigned int x_ppem = font->x_ppem;
247 0 : unsigned int y_ppem = font->y_ppem;
248 : hb_position_t cx, cy;
249 0 : hb_bool_t ret = false;
250 :
251 0 : if (x_ppem || y_ppem)
252 0 : ret = hb_font_get_glyph_contour_point_for_origin (font, glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
253 0 : *x = x_ppem && ret ? cx : font->em_scale_x (xCoordinate);
254 0 : *y = y_ppem && ret ? cy : font->em_scale_y (yCoordinate);
255 0 : }
256 :
257 0 : inline bool sanitize (hb_sanitize_context_t *c) {
258 0 : TRACE_SANITIZE ();
259 0 : return c->check_struct (this);
260 : }
261 :
262 : private:
263 : USHORT format; /* Format identifier--format = 2 */
264 : SHORT xCoordinate; /* Horizontal value--in design units */
265 : SHORT yCoordinate; /* Vertical value--in design units */
266 : USHORT anchorPoint; /* Index to glyph contour point */
267 : public:
268 : DEFINE_SIZE_STATIC (8);
269 : };
270 :
271 : struct AnchorFormat3
272 : {
273 : friend struct Anchor;
274 :
275 : private:
276 0 : inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
277 : hb_position_t *x, hb_position_t *y) const
278 : {
279 0 : *x = font->em_scale_x (xCoordinate);
280 0 : *y = font->em_scale_y (yCoordinate);
281 :
282 0 : if (font->x_ppem)
283 0 : *x += (this+xDeviceTable).get_x_delta (font);
284 0 : if (font->y_ppem)
285 0 : *y += (this+yDeviceTable).get_x_delta (font);
286 0 : }
287 :
288 0 : inline bool sanitize (hb_sanitize_context_t *c) {
289 0 : TRACE_SANITIZE ();
290 0 : return c->check_struct (this)
291 0 : && xDeviceTable.sanitize (c, this)
292 0 : && yDeviceTable.sanitize (c, this);
293 : }
294 :
295 : private:
296 : USHORT format; /* Format identifier--format = 3 */
297 : SHORT xCoordinate; /* Horizontal value--in design units */
298 : SHORT yCoordinate; /* Vertical value--in design units */
299 : OffsetTo<Device>
300 : xDeviceTable; /* Offset to Device table for X
301 : * coordinate-- from beginning of
302 : * Anchor table (may be NULL) */
303 : OffsetTo<Device>
304 : yDeviceTable; /* Offset to Device table for Y
305 : * coordinate-- from beginning of
306 : * Anchor table (may be NULL) */
307 : public:
308 : DEFINE_SIZE_STATIC (10);
309 : };
310 :
311 : struct Anchor
312 : {
313 0 : inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
314 : hb_position_t *x, hb_position_t *y) const
315 : {
316 0 : *x = *y = 0;
317 0 : switch (u.format) {
318 0 : case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
319 0 : case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
320 0 : case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
321 0 : default: return;
322 : }
323 : }
324 :
325 0 : inline bool sanitize (hb_sanitize_context_t *c) {
326 0 : TRACE_SANITIZE ();
327 0 : if (!u.format.sanitize (c)) return false;
328 0 : switch (u.format) {
329 0 : case 1: return u.format1.sanitize (c);
330 0 : case 2: return u.format2.sanitize (c);
331 0 : case 3: return u.format3.sanitize (c);
332 0 : default:return true;
333 : }
334 : }
335 :
336 : private:
337 : union {
338 : USHORT format; /* Format identifier */
339 : AnchorFormat1 format1;
340 : AnchorFormat2 format2;
341 : AnchorFormat3 format3;
342 : } u;
343 : public:
344 : DEFINE_SIZE_UNION (2, format);
345 : };
346 :
347 :
348 : struct AnchorMatrix
349 : {
350 0 : inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols) const {
351 0 : if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
352 0 : return this+matrix[row * cols + col];
353 : }
354 :
355 0 : inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
356 0 : TRACE_SANITIZE ();
357 0 : if (!c->check_struct (this)) return false;
358 0 : if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return false;
359 0 : unsigned int count = rows * cols;
360 0 : if (!c->check_array (matrix, matrix[0].static_size, count)) return false;
361 0 : for (unsigned int i = 0; i < count; i++)
362 0 : if (!matrix[i].sanitize (c, this)) return false;
363 0 : return true;
364 : }
365 :
366 : USHORT rows; /* Number of rows */
367 : private:
368 : OffsetTo<Anchor>
369 : matrix[VAR]; /* Matrix of offsets to Anchor tables--
370 : * from beginning of AnchorMatrix table */
371 : public:
372 : DEFINE_SIZE_ARRAY (2, matrix);
373 : };
374 :
375 :
376 : struct MarkRecord
377 : {
378 : friend struct MarkArray;
379 :
380 0 : inline bool sanitize (hb_sanitize_context_t *c, void *base) {
381 0 : TRACE_SANITIZE ();
382 0 : return c->check_struct (this)
383 0 : && markAnchor.sanitize (c, base);
384 : }
385 :
386 : private:
387 : USHORT klass; /* Class defined for this mark */
388 : OffsetTo<Anchor>
389 : markAnchor; /* Offset to Anchor table--from
390 : * beginning of MarkArray table */
391 : public:
392 : DEFINE_SIZE_STATIC (4);
393 : };
394 :
395 : struct MarkArray : ArrayOf<MarkRecord> /* Array of MarkRecords--in Coverage order */
396 : {
397 0 : inline bool apply (hb_apply_context_t *c,
398 : unsigned int mark_index, unsigned int glyph_index,
399 : const AnchorMatrix &anchors, unsigned int class_count,
400 : unsigned int glyph_pos) const
401 : {
402 0 : TRACE_APPLY ();
403 0 : const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
404 0 : unsigned int mark_class = record.klass;
405 :
406 0 : const Anchor& mark_anchor = this + record.markAnchor;
407 0 : const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count);
408 :
409 : hb_position_t mark_x, mark_y, base_x, base_y;
410 :
411 0 : mark_anchor.get_anchor (c->font, c->buffer->info[c->buffer->idx].codepoint, &mark_x, &mark_y);
412 0 : glyph_anchor.get_anchor (c->font, c->buffer->info[glyph_pos].codepoint, &base_x, &base_y);
413 :
414 0 : hb_glyph_position_t &o = c->buffer->pos[c->buffer->idx];
415 0 : o.x_offset = base_x - mark_x;
416 0 : o.y_offset = base_y - mark_y;
417 0 : o.attach_lookback() = c->buffer->idx - glyph_pos;
418 :
419 0 : c->buffer->idx++;
420 0 : return true;
421 : }
422 :
423 0 : inline bool sanitize (hb_sanitize_context_t *c) {
424 0 : TRACE_SANITIZE ();
425 0 : return ArrayOf<MarkRecord>::sanitize (c, this);
426 : }
427 : };
428 :
429 :
430 : /* Lookups */
431 :
432 : struct SinglePosFormat1
433 : {
434 : friend struct SinglePos;
435 :
436 : private:
437 0 : inline bool apply (hb_apply_context_t *c) const
438 : {
439 0 : TRACE_APPLY ();
440 0 : unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
441 0 : if (likely (index == NOT_COVERED))
442 0 : return false;
443 :
444 : valueFormat.apply_value (c->font, c->direction, this,
445 0 : values, c->buffer->pos[c->buffer->idx]);
446 :
447 0 : c->buffer->idx++;
448 0 : return true;
449 : }
450 :
451 0 : inline bool sanitize (hb_sanitize_context_t *c) {
452 0 : TRACE_SANITIZE ();
453 0 : return c->check_struct (this)
454 0 : && coverage.sanitize (c, this)
455 0 : && valueFormat.sanitize_value (c, this, values);
456 : }
457 :
458 : private:
459 : USHORT format; /* Format identifier--format = 1 */
460 : OffsetTo<Coverage>
461 : coverage; /* Offset to Coverage table--from
462 : * beginning of subtable */
463 : ValueFormat valueFormat; /* Defines the types of data in the
464 : * ValueRecord */
465 : ValueRecord values; /* Defines positioning
466 : * value(s)--applied to all glyphs in
467 : * the Coverage table */
468 : public:
469 : DEFINE_SIZE_ARRAY (6, values);
470 : };
471 :
472 : struct SinglePosFormat2
473 : {
474 : friend struct SinglePos;
475 :
476 : private:
477 0 : inline bool apply (hb_apply_context_t *c) const
478 : {
479 0 : TRACE_APPLY ();
480 0 : unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
481 0 : if (likely (index == NOT_COVERED))
482 0 : return false;
483 :
484 0 : if (likely (index >= valueCount))
485 0 : return false;
486 :
487 : valueFormat.apply_value (c->font, c->direction, this,
488 0 : &values[index * valueFormat.get_len ()],
489 0 : c->buffer->pos[c->buffer->idx]);
490 :
491 0 : c->buffer->idx++;
492 0 : return true;
493 : }
494 :
495 0 : inline bool sanitize (hb_sanitize_context_t *c) {
496 0 : TRACE_SANITIZE ();
497 0 : return c->check_struct (this)
498 0 : && coverage.sanitize (c, this)
499 0 : && valueFormat.sanitize_values (c, this, values, valueCount);
500 : }
501 :
502 : private:
503 : USHORT format; /* Format identifier--format = 2 */
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 : USHORT valueCount; /* Number of ValueRecords */
510 : ValueRecord values; /* Array of ValueRecords--positioning
511 : * values applied to glyphs */
512 : public:
513 : DEFINE_SIZE_ARRAY (8, values);
514 : };
515 :
516 : struct SinglePos
517 : {
518 : friend struct PosLookupSubTable;
519 :
520 : private:
521 0 : inline bool apply (hb_apply_context_t *c) const
522 : {
523 0 : TRACE_APPLY ();
524 0 : switch (u.format) {
525 0 : case 1: return u.format1.apply (c);
526 0 : case 2: return u.format2.apply (c);
527 0 : default:return false;
528 : }
529 : }
530 :
531 0 : inline bool sanitize (hb_sanitize_context_t *c) {
532 0 : TRACE_SANITIZE ();
533 0 : if (!u.format.sanitize (c)) return false;
534 0 : switch (u.format) {
535 0 : case 1: return u.format1.sanitize (c);
536 0 : case 2: return u.format2.sanitize (c);
537 0 : default:return true;
538 : }
539 : }
540 :
541 : private:
542 : union {
543 : USHORT format; /* Format identifier */
544 : SinglePosFormat1 format1;
545 : SinglePosFormat2 format2;
546 : } u;
547 : };
548 :
549 :
550 : struct PairValueRecord
551 : {
552 : friend struct PairSet;
553 :
554 : private:
555 : GlyphID secondGlyph; /* GlyphID of second glyph in the
556 : * pair--first glyph is listed in the
557 : * Coverage table */
558 : ValueRecord values; /* Positioning data for the first glyph
559 : * followed by for second glyph */
560 : public:
561 : DEFINE_SIZE_ARRAY (2, values);
562 : };
563 :
564 : struct PairSet
565 : {
566 : friend struct PairPosFormat1;
567 :
568 0 : inline bool apply (hb_apply_context_t *c,
569 : const ValueFormat *valueFormats,
570 : unsigned int pos) const
571 : {
572 0 : TRACE_APPLY ();
573 0 : unsigned int len1 = valueFormats[0].get_len ();
574 0 : unsigned int len2 = valueFormats[1].get_len ();
575 0 : unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
576 :
577 0 : unsigned int count = len;
578 0 : const PairValueRecord *record = CastP<PairValueRecord> (array);
579 0 : for (unsigned int i = 0; i < count; i++)
580 : {
581 0 : if (c->buffer->info[pos].codepoint == record->secondGlyph)
582 : {
583 : valueFormats[0].apply_value (c->font, c->direction, this,
584 0 : &record->values[0], c->buffer->pos[c->buffer->idx]);
585 : valueFormats[1].apply_value (c->font, c->direction, this,
586 0 : &record->values[len1], c->buffer->pos[pos]);
587 0 : if (len2)
588 0 : pos++;
589 0 : c->buffer->idx = pos;
590 0 : return true;
591 : }
592 0 : record = &StructAtOffset<PairValueRecord> (record, record_size);
593 : }
594 :
595 0 : return false;
596 : }
597 :
598 : struct sanitize_closure_t {
599 : void *base;
600 : ValueFormat *valueFormats;
601 : unsigned int len1; /* valueFormats[0].get_len() */
602 : unsigned int stride; /* 1 + len1 + len2 */
603 : };
604 :
605 0 : inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
606 0 : TRACE_SANITIZE ();
607 0 : if (!(c->check_struct (this)
608 0 : && c->check_array (array, USHORT::static_size * closure->stride, len))) return false;
609 :
610 0 : unsigned int count = len;
611 0 : PairValueRecord *record = CastP<PairValueRecord> (array);
612 0 : return closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
613 0 : && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride);
614 : }
615 :
616 : private:
617 : USHORT len; /* Number of PairValueRecords */
618 : USHORT array[VAR]; /* Array of PairValueRecords--ordered
619 : * by GlyphID of the second glyph */
620 : public:
621 : DEFINE_SIZE_ARRAY (2, array);
622 : };
623 :
624 : struct PairPosFormat1
625 : {
626 : friend struct PairPos;
627 :
628 : private:
629 0 : inline bool apply (hb_apply_context_t *c) const
630 : {
631 0 : TRACE_APPLY ();
632 0 : hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
633 0 : if (skippy_iter.has_no_chance ())
634 0 : return false;
635 :
636 0 : unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
637 0 : if (likely (index == NOT_COVERED))
638 0 : return false;
639 :
640 0 : if (!skippy_iter.next ())
641 0 : return false;
642 :
643 0 : return (this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx);
644 : }
645 :
646 0 : inline bool sanitize (hb_sanitize_context_t *c) {
647 0 : TRACE_SANITIZE ();
648 :
649 0 : unsigned int len1 = valueFormat1.get_len ();
650 0 : unsigned int len2 = valueFormat2.get_len ();
651 : PairSet::sanitize_closure_t closure = {
652 : this,
653 : &valueFormat1,
654 : len1,
655 : 1 + len1 + len2
656 0 : };
657 :
658 0 : return c->check_struct (this)
659 0 : && coverage.sanitize (c, this)
660 0 : && pairSet.sanitize (c, this, &closure);
661 : }
662 :
663 : private:
664 : USHORT format; /* Format identifier--format = 1 */
665 : OffsetTo<Coverage>
666 : coverage; /* Offset to Coverage table--from
667 : * beginning of subtable */
668 : ValueFormat valueFormat1; /* Defines the types of data in
669 : * ValueRecord1--for the first glyph
670 : * in the pair--may be zero (0) */
671 : ValueFormat valueFormat2; /* Defines the types of data in
672 : * ValueRecord2--for the second glyph
673 : * in the pair--may be zero (0) */
674 : OffsetArrayOf<PairSet>
675 : pairSet; /* Array of PairSet tables
676 : * ordered by Coverage Index */
677 : public:
678 : DEFINE_SIZE_ARRAY (10, pairSet);
679 : };
680 :
681 : struct PairPosFormat2
682 : {
683 : friend struct PairPos;
684 :
685 : private:
686 0 : inline bool apply (hb_apply_context_t *c) const
687 : {
688 0 : TRACE_APPLY ();
689 0 : hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
690 0 : if (skippy_iter.has_no_chance ())
691 0 : return false;
692 :
693 0 : unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
694 0 : if (likely (index == NOT_COVERED))
695 0 : return false;
696 :
697 0 : if (!skippy_iter.next ())
698 0 : return false;
699 :
700 0 : unsigned int len1 = valueFormat1.get_len ();
701 0 : unsigned int len2 = valueFormat2.get_len ();
702 0 : unsigned int record_len = len1 + len2;
703 :
704 0 : unsigned int klass1 = (this+classDef1) (c->buffer->info[c->buffer->idx].codepoint);
705 0 : unsigned int klass2 = (this+classDef2) (c->buffer->info[skippy_iter.idx].codepoint);
706 0 : if (unlikely (klass1 >= class1Count || klass2 >= class2Count))
707 0 : return false;
708 :
709 0 : const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
710 : valueFormat1.apply_value (c->font, c->direction, this,
711 0 : v, c->buffer->pos[c->buffer->idx]);
712 : valueFormat2.apply_value (c->font, c->direction, this,
713 0 : v + len1, c->buffer->pos[skippy_iter.idx]);
714 :
715 0 : c->buffer->idx = skippy_iter.idx;
716 0 : if (len2)
717 0 : c->buffer->idx++;
718 :
719 0 : return true;
720 : }
721 :
722 0 : inline bool sanitize (hb_sanitize_context_t *c) {
723 0 : TRACE_SANITIZE ();
724 0 : if (!(c->check_struct (this)
725 0 : && coverage.sanitize (c, this)
726 0 : && classDef1.sanitize (c, this)
727 0 : && classDef2.sanitize (c, this))) return false;
728 :
729 0 : unsigned int len1 = valueFormat1.get_len ();
730 0 : unsigned int len2 = valueFormat2.get_len ();
731 0 : unsigned int stride = len1 + len2;
732 0 : unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
733 0 : unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
734 0 : return c->check_array (values, record_size, count) &&
735 0 : valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
736 0 : valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride);
737 : }
738 :
739 : private:
740 : USHORT format; /* Format identifier--format = 2 */
741 : OffsetTo<Coverage>
742 : coverage; /* Offset to Coverage table--from
743 : * beginning of subtable */
744 : ValueFormat valueFormat1; /* ValueRecord definition--for the
745 : * first glyph of the pair--may be zero
746 : * (0) */
747 : ValueFormat valueFormat2; /* ValueRecord definition--for the
748 : * second glyph of the pair--may be
749 : * zero (0) */
750 : OffsetTo<ClassDef>
751 : classDef1; /* Offset to ClassDef table--from
752 : * beginning of PairPos subtable--for
753 : * the first glyph of the pair */
754 : OffsetTo<ClassDef>
755 : classDef2; /* Offset to ClassDef table--from
756 : * beginning of PairPos subtable--for
757 : * the second glyph of the pair */
758 : USHORT class1Count; /* Number of classes in ClassDef1
759 : * table--includes Class0 */
760 : USHORT class2Count; /* Number of classes in ClassDef2
761 : * table--includes Class0 */
762 : ValueRecord values; /* Matrix of value pairs:
763 : * class1-major, class2-minor,
764 : * Each entry has value1 and value2 */
765 : public:
766 : DEFINE_SIZE_ARRAY (16, values);
767 : };
768 :
769 : struct PairPos
770 : {
771 : friend struct PosLookupSubTable;
772 :
773 : private:
774 0 : inline bool apply (hb_apply_context_t *c) const
775 : {
776 0 : TRACE_APPLY ();
777 0 : switch (u.format) {
778 0 : case 1: return u.format1.apply (c);
779 0 : case 2: return u.format2.apply (c);
780 0 : default:return false;
781 : }
782 : }
783 :
784 0 : inline bool sanitize (hb_sanitize_context_t *c) {
785 0 : TRACE_SANITIZE ();
786 0 : if (!u.format.sanitize (c)) return false;
787 0 : switch (u.format) {
788 0 : case 1: return u.format1.sanitize (c);
789 0 : case 2: return u.format2.sanitize (c);
790 0 : default:return true;
791 : }
792 : }
793 :
794 : private:
795 : union {
796 : USHORT format; /* Format identifier */
797 : PairPosFormat1 format1;
798 : PairPosFormat2 format2;
799 : } u;
800 : };
801 :
802 :
803 : struct EntryExitRecord
804 : {
805 : friend struct CursivePosFormat1;
806 :
807 0 : inline bool sanitize (hb_sanitize_context_t *c, void *base) {
808 0 : TRACE_SANITIZE ();
809 0 : return entryAnchor.sanitize (c, base)
810 0 : && exitAnchor.sanitize (c, base);
811 : }
812 :
813 : private:
814 : OffsetTo<Anchor>
815 : entryAnchor; /* Offset to EntryAnchor table--from
816 : * beginning of CursivePos
817 : * subtable--may be NULL */
818 : OffsetTo<Anchor>
819 : exitAnchor; /* Offset to ExitAnchor table--from
820 : * beginning of CursivePos
821 : * subtable--may be NULL */
822 : public:
823 : DEFINE_SIZE_STATIC (4);
824 : };
825 :
826 : struct CursivePosFormat1
827 : {
828 : friend struct CursivePos;
829 :
830 : private:
831 0 : inline bool apply (hb_apply_context_t *c) const
832 : {
833 0 : TRACE_APPLY ();
834 :
835 : /* We don't handle mark glyphs here. */
836 0 : if (c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK)
837 0 : return false;
838 :
839 0 : hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, 1);
840 0 : if (skippy_iter.has_no_chance ())
841 0 : return false;
842 :
843 0 : const EntryExitRecord &this_record = entryExitRecord[(this+coverage) (c->buffer->info[c->buffer->idx].codepoint)];
844 0 : if (!this_record.exitAnchor)
845 0 : return false;
846 :
847 0 : if (!skippy_iter.next ())
848 0 : return false;
849 :
850 0 : const EntryExitRecord &next_record = entryExitRecord[(this+coverage) (c->buffer->info[skippy_iter.idx].codepoint)];
851 0 : if (!next_record.entryAnchor)
852 0 : return false;
853 :
854 0 : unsigned int i = c->buffer->idx;
855 0 : unsigned int j = skippy_iter.idx;
856 :
857 : hb_position_t entry_x, entry_y, exit_x, exit_y;
858 0 : (this+this_record.exitAnchor).get_anchor (c->font, c->buffer->info[i].codepoint, &exit_x, &exit_y);
859 0 : (this+next_record.entryAnchor).get_anchor (c->font, c->buffer->info[j].codepoint, &entry_x, &entry_y);
860 :
861 0 : hb_glyph_position_t *pos = c->buffer->pos;
862 :
863 : hb_position_t d;
864 : /* Main-direction adjustment */
865 0 : switch (c->direction) {
866 : case HB_DIRECTION_LTR:
867 0 : pos[i].x_advance = exit_x + pos[i].x_offset;
868 :
869 0 : d = entry_x + pos[j].x_offset;
870 0 : pos[j].x_advance -= d;
871 0 : pos[j].x_offset -= d;
872 0 : break;
873 : case HB_DIRECTION_RTL:
874 0 : d = exit_x + pos[i].x_offset;
875 0 : pos[i].x_advance -= d;
876 0 : pos[i].x_offset -= d;
877 :
878 0 : pos[j].x_advance = entry_x + pos[j].x_offset;
879 0 : break;
880 : case HB_DIRECTION_TTB:
881 0 : pos[i].y_advance = exit_y + pos[i].y_offset;
882 :
883 0 : d = entry_y + pos[j].y_offset;
884 0 : pos[j].y_advance -= d;
885 0 : pos[j].y_offset -= d;
886 0 : break;
887 : case HB_DIRECTION_BTT:
888 0 : d = exit_y + pos[i].y_offset;
889 0 : pos[i].y_advance -= d;
890 0 : pos[i].y_offset -= d;
891 :
892 0 : pos[j].y_advance = entry_y;
893 0 : break;
894 : case HB_DIRECTION_INVALID:
895 : default:
896 0 : break;
897 : }
898 :
899 : /* Cross-direction adjustment */
900 0 : if (c->lookup_props & LookupFlag::RightToLeft) {
901 0 : pos[i].cursive_chain() = j - i;
902 0 : if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
903 0 : pos[i].y_offset = entry_y - exit_y;
904 : else
905 0 : pos[i].x_offset = entry_x - exit_x;
906 : } else {
907 0 : pos[j].cursive_chain() = i - j;
908 0 : if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
909 0 : pos[j].y_offset = exit_y - entry_y;
910 : else
911 0 : pos[j].x_offset = exit_x - entry_x;
912 : }
913 :
914 0 : c->buffer->idx = j;
915 0 : return true;
916 : }
917 :
918 0 : inline bool sanitize (hb_sanitize_context_t *c) {
919 0 : TRACE_SANITIZE ();
920 0 : return coverage.sanitize (c, this)
921 0 : && entryExitRecord.sanitize (c, this);
922 : }
923 :
924 : private:
925 : USHORT format; /* Format identifier--format = 1 */
926 : OffsetTo<Coverage>
927 : coverage; /* Offset to Coverage table--from
928 : * beginning of subtable */
929 : ArrayOf<EntryExitRecord>
930 : entryExitRecord; /* Array of EntryExit records--in
931 : * Coverage Index order */
932 : public:
933 : DEFINE_SIZE_ARRAY (6, entryExitRecord);
934 : };
935 :
936 : struct CursivePos
937 : {
938 : friend struct PosLookupSubTable;
939 :
940 : private:
941 0 : inline bool apply (hb_apply_context_t *c) const
942 : {
943 0 : TRACE_APPLY ();
944 0 : switch (u.format) {
945 0 : case 1: return u.format1.apply (c);
946 0 : default:return false;
947 : }
948 : }
949 :
950 0 : inline bool sanitize (hb_sanitize_context_t *c) {
951 0 : TRACE_SANITIZE ();
952 0 : if (!u.format.sanitize (c)) return false;
953 0 : switch (u.format) {
954 0 : case 1: return u.format1.sanitize (c);
955 0 : default:return true;
956 : }
957 : }
958 :
959 : private:
960 : union {
961 : USHORT format; /* Format identifier */
962 : CursivePosFormat1 format1;
963 : } u;
964 : };
965 :
966 :
967 : typedef AnchorMatrix BaseArray; /* base-major--
968 : * in order of BaseCoverage Index--,
969 : * mark-minor--
970 : * ordered by class--zero-based. */
971 :
972 : struct MarkBasePosFormat1
973 : {
974 : friend struct MarkBasePos;
975 :
976 : private:
977 0 : inline bool apply (hb_apply_context_t *c) const
978 : {
979 0 : TRACE_APPLY ();
980 0 : unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].codepoint);
981 0 : if (likely (mark_index == NOT_COVERED))
982 0 : return false;
983 :
984 : /* now we search backwards for a non-mark glyph */
985 : unsigned int property;
986 0 : hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
987 0 : if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks))
988 0 : return false;
989 :
990 : /* The following assertion is too strong, so we've disabled it. */
991 0 : if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH))
992 : {/*return false;*/}
993 :
994 0 : unsigned int base_index = (this+baseCoverage) (c->buffer->info[skippy_iter.idx].codepoint);
995 0 : if (base_index == NOT_COVERED)
996 0 : return false;
997 :
998 0 : return (this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx);
999 : }
1000 :
1001 0 : inline bool sanitize (hb_sanitize_context_t *c) {
1002 0 : TRACE_SANITIZE ();
1003 0 : return c->check_struct (this)
1004 0 : && markCoverage.sanitize (c, this)
1005 0 : && baseCoverage.sanitize (c, this)
1006 0 : && markArray.sanitize (c, this)
1007 0 : && baseArray.sanitize (c, this, (unsigned int) classCount);
1008 : }
1009 :
1010 : private:
1011 : USHORT format; /* Format identifier--format = 1 */
1012 : OffsetTo<Coverage>
1013 : markCoverage; /* Offset to MarkCoverage table--from
1014 : * beginning of MarkBasePos subtable */
1015 : OffsetTo<Coverage>
1016 : baseCoverage; /* Offset to BaseCoverage table--from
1017 : * beginning of MarkBasePos subtable */
1018 : USHORT classCount; /* Number of classes defined for marks */
1019 : OffsetTo<MarkArray>
1020 : markArray; /* Offset to MarkArray table--from
1021 : * beginning of MarkBasePos subtable */
1022 : OffsetTo<BaseArray>
1023 : baseArray; /* Offset to BaseArray table--from
1024 : * beginning of MarkBasePos subtable */
1025 : public:
1026 : DEFINE_SIZE_STATIC (12);
1027 : };
1028 :
1029 : struct MarkBasePos
1030 : {
1031 : friend struct PosLookupSubTable;
1032 :
1033 : private:
1034 0 : inline bool apply (hb_apply_context_t *c) const
1035 : {
1036 0 : TRACE_APPLY ();
1037 0 : switch (u.format) {
1038 0 : case 1: return u.format1.apply (c);
1039 0 : default:return false;
1040 : }
1041 : }
1042 :
1043 0 : inline bool sanitize (hb_sanitize_context_t *c) {
1044 0 : TRACE_SANITIZE ();
1045 0 : if (!u.format.sanitize (c)) return false;
1046 0 : switch (u.format) {
1047 0 : case 1: return u.format1.sanitize (c);
1048 0 : default:return true;
1049 : }
1050 : }
1051 :
1052 : private:
1053 : union {
1054 : USHORT format; /* Format identifier */
1055 : MarkBasePosFormat1 format1;
1056 : } u;
1057 : };
1058 :
1059 :
1060 : typedef AnchorMatrix LigatureAttach; /* component-major--
1061 : * in order of writing direction--,
1062 : * mark-minor--
1063 : * ordered by class--zero-based. */
1064 :
1065 : typedef OffsetListOf<LigatureAttach> LigatureArray;
1066 : /* Array of LigatureAttach
1067 : * tables ordered by
1068 : * LigatureCoverage Index */
1069 :
1070 : struct MarkLigPosFormat1
1071 : {
1072 : friend struct MarkLigPos;
1073 :
1074 : private:
1075 0 : inline bool apply (hb_apply_context_t *c) const
1076 : {
1077 0 : TRACE_APPLY ();
1078 0 : unsigned int mark_index = (this+markCoverage) (c->buffer->info[c->buffer->idx].codepoint);
1079 0 : if (likely (mark_index == NOT_COVERED))
1080 0 : return false;
1081 :
1082 : /* now we search backwards for a non-mark glyph */
1083 : unsigned int property;
1084 0 : hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1085 0 : if (!skippy_iter.prev (&property, LookupFlag::IgnoreMarks))
1086 0 : return false;
1087 :
1088 : /* The following assertion is too strong, so we've disabled it. */
1089 0 : if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE))
1090 : {/*return false;*/}
1091 :
1092 0 : unsigned int j = skippy_iter.idx;
1093 0 : unsigned int lig_index = (this+ligatureCoverage) (c->buffer->info[j].codepoint);
1094 0 : if (lig_index == NOT_COVERED)
1095 0 : return false;
1096 :
1097 0 : const LigatureArray& lig_array = this+ligatureArray;
1098 0 : const LigatureAttach& lig_attach = lig_array[lig_index];
1099 :
1100 : /* Find component to attach to */
1101 0 : unsigned int comp_count = lig_attach.rows;
1102 0 : if (unlikely (!comp_count))
1103 0 : return false;
1104 : unsigned int comp_index;
1105 : /* We must now check whether the ligature ID of the current mark glyph
1106 : * is identical to the ligature ID of the found ligature. If yes, we
1107 : * can directly use the component index. If not, we attach the mark
1108 : * glyph to the last component of the ligature. */
1109 0 : if (c->buffer->info[j].lig_id() && c->buffer->info[j].lig_id() == c->buffer->info[c->buffer->idx].lig_id() && c->buffer->info[c->buffer->idx].lig_comp())
1110 : {
1111 0 : comp_index = c->buffer->info[c->buffer->idx].lig_comp() - 1;
1112 0 : if (comp_index >= comp_count)
1113 0 : comp_index = comp_count - 1;
1114 : }
1115 : else
1116 0 : comp_index = comp_count - 1;
1117 :
1118 0 : return (this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j);
1119 : }
1120 :
1121 0 : inline bool sanitize (hb_sanitize_context_t *c) {
1122 0 : TRACE_SANITIZE ();
1123 0 : return c->check_struct (this)
1124 0 : && markCoverage.sanitize (c, this)
1125 0 : && ligatureCoverage.sanitize (c, this)
1126 0 : && markArray.sanitize (c, this)
1127 0 : && ligatureArray.sanitize (c, this, (unsigned int) classCount);
1128 : }
1129 :
1130 : private:
1131 : USHORT format; /* Format identifier--format = 1 */
1132 : OffsetTo<Coverage>
1133 : markCoverage; /* Offset to Mark Coverage table--from
1134 : * beginning of MarkLigPos subtable */
1135 : OffsetTo<Coverage>
1136 : ligatureCoverage; /* Offset to Ligature Coverage
1137 : * table--from beginning of MarkLigPos
1138 : * subtable */
1139 : USHORT classCount; /* Number of defined mark classes */
1140 : OffsetTo<MarkArray>
1141 : markArray; /* Offset to MarkArray table--from
1142 : * beginning of MarkLigPos subtable */
1143 : OffsetTo<LigatureArray>
1144 : ligatureArray; /* Offset to LigatureArray table--from
1145 : * beginning of MarkLigPos subtable */
1146 : public:
1147 : DEFINE_SIZE_STATIC (12);
1148 : };
1149 :
1150 : struct MarkLigPos
1151 : {
1152 : friend struct PosLookupSubTable;
1153 :
1154 : private:
1155 0 : inline bool apply (hb_apply_context_t *c) const
1156 : {
1157 0 : TRACE_APPLY ();
1158 0 : switch (u.format) {
1159 0 : case 1: return u.format1.apply (c);
1160 0 : default:return false;
1161 : }
1162 : }
1163 :
1164 0 : inline bool sanitize (hb_sanitize_context_t *c) {
1165 0 : TRACE_SANITIZE ();
1166 0 : if (!u.format.sanitize (c)) return false;
1167 0 : switch (u.format) {
1168 0 : case 1: return u.format1.sanitize (c);
1169 0 : default:return true;
1170 : }
1171 : }
1172 :
1173 : private:
1174 : union {
1175 : USHORT format; /* Format identifier */
1176 : MarkLigPosFormat1 format1;
1177 : } u;
1178 : };
1179 :
1180 :
1181 : typedef AnchorMatrix Mark2Array; /* mark2-major--
1182 : * in order of Mark2Coverage Index--,
1183 : * mark1-minor--
1184 : * ordered by class--zero-based. */
1185 :
1186 : struct MarkMarkPosFormat1
1187 : {
1188 : friend struct MarkMarkPos;
1189 :
1190 : private:
1191 0 : inline bool apply (hb_apply_context_t *c) const
1192 : {
1193 0 : TRACE_APPLY ();
1194 0 : unsigned int mark1_index = (this+mark1Coverage) (c->buffer->info[c->buffer->idx].codepoint);
1195 0 : if (likely (mark1_index == NOT_COVERED))
1196 0 : return false;
1197 :
1198 : /* now we search backwards for a suitable mark glyph until a non-mark glyph */
1199 : unsigned int property;
1200 0 : hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->idx, 1);
1201 0 : if (!skippy_iter.prev (&property))
1202 0 : return false;
1203 :
1204 0 : if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
1205 0 : return false;
1206 :
1207 0 : unsigned int j = skippy_iter.idx;
1208 :
1209 : /* Two marks match only if they belong to the same base, or same component
1210 : * of the same ligature. That is, the component numbers must match, and
1211 : * if those are non-zero, the ligid number should also match. */
1212 0 : if ((c->buffer->info[j].lig_comp() != c->buffer->info[c->buffer->idx].lig_comp()) ||
1213 0 : (c->buffer->info[j].lig_comp() && c->buffer->info[j].lig_id() != c->buffer->info[c->buffer->idx].lig_id()))
1214 0 : return false;
1215 :
1216 0 : unsigned int mark2_index = (this+mark2Coverage) (c->buffer->info[j].codepoint);
1217 0 : if (mark2_index == NOT_COVERED)
1218 0 : return false;
1219 :
1220 0 : return (this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j);
1221 : }
1222 :
1223 0 : inline bool sanitize (hb_sanitize_context_t *c) {
1224 0 : TRACE_SANITIZE ();
1225 0 : return c->check_struct (this)
1226 0 : && mark1Coverage.sanitize (c, this)
1227 0 : && mark2Coverage.sanitize (c, this)
1228 0 : && mark1Array.sanitize (c, this)
1229 0 : && mark2Array.sanitize (c, this, (unsigned int) classCount);
1230 : }
1231 :
1232 : private:
1233 : USHORT format; /* Format identifier--format = 1 */
1234 : OffsetTo<Coverage>
1235 : mark1Coverage; /* Offset to Combining Mark1 Coverage
1236 : * table--from beginning of MarkMarkPos
1237 : * subtable */
1238 : OffsetTo<Coverage>
1239 : mark2Coverage; /* Offset to Combining Mark2 Coverage
1240 : * table--from beginning of MarkMarkPos
1241 : * subtable */
1242 : USHORT classCount; /* Number of defined mark classes */
1243 : OffsetTo<MarkArray>
1244 : mark1Array; /* Offset to Mark1Array table--from
1245 : * beginning of MarkMarkPos subtable */
1246 : OffsetTo<Mark2Array>
1247 : mark2Array; /* Offset to Mark2Array table--from
1248 : * beginning of MarkMarkPos subtable */
1249 : public:
1250 : DEFINE_SIZE_STATIC (12);
1251 : };
1252 :
1253 : struct MarkMarkPos
1254 : {
1255 : friend struct PosLookupSubTable;
1256 :
1257 : private:
1258 0 : inline bool apply (hb_apply_context_t *c) const
1259 : {
1260 0 : TRACE_APPLY ();
1261 0 : switch (u.format) {
1262 0 : case 1: return u.format1.apply (c);
1263 0 : default:return false;
1264 : }
1265 : }
1266 :
1267 0 : inline bool sanitize (hb_sanitize_context_t *c) {
1268 0 : TRACE_SANITIZE ();
1269 0 : if (!u.format.sanitize (c)) return false;
1270 0 : switch (u.format) {
1271 0 : case 1: return u.format1.sanitize (c);
1272 0 : default:return true;
1273 : }
1274 : }
1275 :
1276 : private:
1277 : union {
1278 : USHORT format; /* Format identifier */
1279 : MarkMarkPosFormat1 format1;
1280 : } u;
1281 : };
1282 :
1283 :
1284 : static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index);
1285 :
1286 : struct ContextPos : Context
1287 : {
1288 : friend struct PosLookupSubTable;
1289 :
1290 : private:
1291 0 : inline bool apply (hb_apply_context_t *c) const
1292 : {
1293 0 : TRACE_APPLY ();
1294 0 : return Context::apply (c, position_lookup);
1295 : }
1296 : };
1297 :
1298 : struct ChainContextPos : ChainContext
1299 : {
1300 : friend struct PosLookupSubTable;
1301 :
1302 : private:
1303 0 : inline bool apply (hb_apply_context_t *c) const
1304 : {
1305 0 : TRACE_APPLY ();
1306 0 : return ChainContext::apply (c, position_lookup);
1307 : }
1308 : };
1309 :
1310 :
1311 : struct ExtensionPos : Extension
1312 : {
1313 : friend struct PosLookupSubTable;
1314 :
1315 : private:
1316 0 : inline const struct PosLookupSubTable& get_subtable (void) const
1317 : {
1318 0 : unsigned int offset = get_offset ();
1319 0 : if (unlikely (!offset)) return Null(PosLookupSubTable);
1320 0 : return StructAtOffset<PosLookupSubTable> (this, offset);
1321 : }
1322 :
1323 : inline bool apply (hb_apply_context_t *c) const;
1324 :
1325 : inline bool sanitize (hb_sanitize_context_t *c);
1326 : };
1327 :
1328 :
1329 :
1330 : /*
1331 : * PosLookup
1332 : */
1333 :
1334 :
1335 : struct PosLookupSubTable
1336 : {
1337 : friend struct PosLookup;
1338 :
1339 : enum {
1340 : Single = 1,
1341 : Pair = 2,
1342 : Cursive = 3,
1343 : MarkBase = 4,
1344 : MarkLig = 5,
1345 : MarkMark = 6,
1346 : Context = 7,
1347 : ChainContext = 8,
1348 : Extension = 9
1349 : };
1350 :
1351 0 : inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
1352 : {
1353 0 : TRACE_APPLY ();
1354 0 : switch (lookup_type) {
1355 0 : case Single: return u.single.apply (c);
1356 0 : case Pair: return u.pair.apply (c);
1357 0 : case Cursive: return u.cursive.apply (c);
1358 0 : case MarkBase: return u.markBase.apply (c);
1359 0 : case MarkLig: return u.markLig.apply (c);
1360 0 : case MarkMark: return u.markMark.apply (c);
1361 0 : case Context: return u.c.apply (c);
1362 0 : case ChainContext: return u.chainContext.apply (c);
1363 0 : case Extension: return u.extension.apply (c);
1364 0 : default:return false;
1365 : }
1366 : }
1367 :
1368 0 : inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
1369 0 : TRACE_SANITIZE ();
1370 0 : switch (lookup_type) {
1371 0 : case Single: return u.single.sanitize (c);
1372 0 : case Pair: return u.pair.sanitize (c);
1373 0 : case Cursive: return u.cursive.sanitize (c);
1374 0 : case MarkBase: return u.markBase.sanitize (c);
1375 0 : case MarkLig: return u.markLig.sanitize (c);
1376 0 : case MarkMark: return u.markMark.sanitize (c);
1377 0 : case Context: return u.c.sanitize (c);
1378 0 : case ChainContext: return u.chainContext.sanitize (c);
1379 0 : case Extension: return u.extension.sanitize (c);
1380 0 : default:return true;
1381 : }
1382 : }
1383 :
1384 : private:
1385 : union {
1386 : USHORT sub_format;
1387 : SinglePos single;
1388 : PairPos pair;
1389 : CursivePos cursive;
1390 : MarkBasePos markBase;
1391 : MarkLigPos markLig;
1392 : MarkMarkPos markMark;
1393 : ContextPos c;
1394 : ChainContextPos chainContext;
1395 : ExtensionPos extension;
1396 : } u;
1397 : public:
1398 : DEFINE_SIZE_UNION (2, sub_format);
1399 : };
1400 :
1401 :
1402 : struct PosLookup : Lookup
1403 : {
1404 0 : inline const PosLookupSubTable& get_subtable (unsigned int i) const
1405 0 : { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
1406 :
1407 0 : inline bool apply_once (hb_font_t *font,
1408 : hb_buffer_t *buffer,
1409 : hb_mask_t lookup_mask,
1410 : unsigned int context_length,
1411 : unsigned int nesting_level_left) const
1412 : {
1413 0 : unsigned int lookup_type = get_type ();
1414 0 : hb_apply_context_t c[1] = {{0}};
1415 :
1416 0 : c->font = font;
1417 0 : c->face = font->face;
1418 0 : c->buffer = buffer;
1419 0 : c->direction = buffer->props.direction;
1420 0 : c->lookup_mask = lookup_mask;
1421 0 : c->context_length = context_length;
1422 0 : c->nesting_level_left = nesting_level_left;
1423 0 : c->lookup_props = get_props ();
1424 :
1425 0 : if (!_hb_ot_layout_check_glyph_property (c->face, &c->buffer->info[c->buffer->idx], c->lookup_props, &c->property))
1426 0 : return false;
1427 :
1428 0 : for (unsigned int i = 0; i < get_subtable_count (); i++)
1429 0 : if (get_subtable (i).apply (c, lookup_type))
1430 0 : return true;
1431 :
1432 0 : return false;
1433 : }
1434 :
1435 0 : inline bool apply_string (hb_font_t *font,
1436 : hb_buffer_t *buffer,
1437 : hb_mask_t mask) const
1438 : {
1439 0 : bool ret = false;
1440 :
1441 0 : if (unlikely (!buffer->len))
1442 0 : return false;
1443 :
1444 0 : buffer->idx = 0;
1445 0 : while (buffer->idx < buffer->len)
1446 : {
1447 0 : if ((buffer->info[buffer->idx].mask & mask) &&
1448 0 : apply_once (font, buffer, mask, NO_CONTEXT, MAX_NESTING_LEVEL))
1449 0 : ret = true;
1450 : else
1451 0 : buffer->idx++;
1452 : }
1453 :
1454 0 : return ret;
1455 : }
1456 :
1457 0 : inline bool sanitize (hb_sanitize_context_t *c) {
1458 0 : TRACE_SANITIZE ();
1459 0 : if (unlikely (!Lookup::sanitize (c))) return false;
1460 0 : OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
1461 0 : return list.sanitize (c, this, get_type ());
1462 : }
1463 : };
1464 :
1465 : typedef OffsetListOf<PosLookup> PosLookupList;
1466 :
1467 : /*
1468 : * GPOS -- The Glyph Positioning Table
1469 : */
1470 :
1471 : struct GPOS : GSUBGPOS
1472 : {
1473 : static const hb_tag_t Tag = HB_OT_TAG_GPOS;
1474 :
1475 0 : inline const PosLookup& get_lookup (unsigned int i) const
1476 0 : { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
1477 :
1478 0 : inline bool position_lookup (hb_font_t *font,
1479 : hb_buffer_t *buffer,
1480 : unsigned int lookup_index,
1481 : hb_mask_t mask) const
1482 0 : { return get_lookup (lookup_index).apply_string (font, buffer, mask); }
1483 :
1484 : static inline void position_start (hb_buffer_t *buffer);
1485 : static inline void position_finish (hb_buffer_t *buffer);
1486 :
1487 0 : inline bool sanitize (hb_sanitize_context_t *c) {
1488 0 : TRACE_SANITIZE ();
1489 0 : if (unlikely (!GSUBGPOS::sanitize (c))) return false;
1490 0 : OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
1491 0 : return list.sanitize (c, this);
1492 : }
1493 : public:
1494 : DEFINE_SIZE_STATIC (10);
1495 : };
1496 :
1497 :
1498 : static void
1499 0 : fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1500 : {
1501 0 : unsigned int j = pos[i].cursive_chain();
1502 0 : if (likely (!j))
1503 0 : return;
1504 :
1505 0 : j += i;
1506 :
1507 0 : pos[i].cursive_chain() = 0;
1508 :
1509 0 : fix_cursive_minor_offset (pos, j, direction);
1510 :
1511 0 : if (HB_DIRECTION_IS_HORIZONTAL (direction))
1512 0 : pos[i].y_offset += pos[j].y_offset;
1513 : else
1514 0 : pos[i].x_offset += pos[j].x_offset;
1515 : }
1516 :
1517 : static void
1518 0 : fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
1519 : {
1520 0 : if (likely (!(pos[i].attach_lookback())))
1521 0 : return;
1522 :
1523 0 : unsigned int j = i - pos[i].attach_lookback();
1524 :
1525 0 : pos[i].x_advance = 0;
1526 0 : pos[i].y_advance = 0;
1527 0 : pos[i].x_offset += pos[j].x_offset;
1528 0 : pos[i].y_offset += pos[j].y_offset;
1529 :
1530 0 : if (HB_DIRECTION_IS_FORWARD (direction))
1531 0 : for (unsigned int k = j; k < i; k++) {
1532 0 : pos[i].x_offset -= pos[k].x_advance;
1533 0 : pos[i].y_offset -= pos[k].y_advance;
1534 : }
1535 : else
1536 0 : for (unsigned int k = j + 1; k < i + 1; k++) {
1537 0 : pos[i].x_offset += pos[k].x_advance;
1538 0 : pos[i].y_offset += pos[k].y_advance;
1539 : }
1540 : }
1541 :
1542 : void
1543 0 : GPOS::position_start (hb_buffer_t *buffer)
1544 : {
1545 0 : buffer->clear_positions ();
1546 :
1547 0 : unsigned int count = buffer->len;
1548 0 : for (unsigned int i = 0; i < count; i++)
1549 0 : buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
1550 0 : }
1551 :
1552 : void
1553 0 : GPOS::position_finish (hb_buffer_t *buffer)
1554 : {
1555 : unsigned int len;
1556 0 : hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
1557 0 : hb_direction_t direction = buffer->props.direction;
1558 :
1559 : /* Handle cursive connections */
1560 0 : for (unsigned int i = 0; i < len; i++)
1561 0 : fix_cursive_minor_offset (pos, i, direction);
1562 :
1563 : /* Handle attachments */
1564 0 : for (unsigned int i = 0; i < len; i++)
1565 0 : fix_mark_attachment (pos, i, direction);
1566 :
1567 0 : HB_BUFFER_DEALLOCATE_VAR (buffer, lig_comp);
1568 0 : HB_BUFFER_DEALLOCATE_VAR (buffer, lig_id);
1569 0 : HB_BUFFER_DEALLOCATE_VAR (buffer, props_cache);
1570 0 : }
1571 :
1572 :
1573 : /* Out-of-class implementation for methods recursing */
1574 :
1575 0 : inline bool ExtensionPos::apply (hb_apply_context_t *c) const
1576 : {
1577 0 : TRACE_APPLY ();
1578 0 : return get_subtable ().apply (c, get_type ());
1579 : }
1580 :
1581 0 : inline bool ExtensionPos::sanitize (hb_sanitize_context_t *c)
1582 : {
1583 0 : TRACE_SANITIZE ();
1584 0 : if (unlikely (!Extension::sanitize (c))) return false;
1585 0 : unsigned int offset = get_offset ();
1586 0 : if (unlikely (!offset)) return true;
1587 0 : return StructAtOffset<PosLookupSubTable> (this, offset).sanitize (c, get_type ());
1588 : }
1589 :
1590 0 : static inline bool position_lookup (hb_apply_context_t *c, unsigned int lookup_index)
1591 : {
1592 0 : const GPOS &gpos = *(c->face->ot_layout->gpos);
1593 0 : const PosLookup &l = gpos.get_lookup (lookup_index);
1594 :
1595 0 : if (unlikely (c->nesting_level_left == 0))
1596 0 : return false;
1597 :
1598 0 : if (unlikely (c->context_length < 1))
1599 0 : return false;
1600 :
1601 0 : return l.apply_once (c->font, c->buffer, c->lookup_mask, c->context_length, c->nesting_level_left - 1);
1602 : }
1603 :
1604 :
1605 : #undef attach_lookback
1606 : #undef cursive_chain
1607 :
1608 :
1609 :
1610 : #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */
|