Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: third_party/harfbuzz-ng/src/hb-ot-layout-gpos-private.hh

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

Powered by Google App Engine
This is Rietveld 408576698